summaryrefslogtreecommitdiffstats
path: root/src/org.gluster.storage.management.console/src
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
commit1142b0e41de39010de7845cf70d71dbb001fc1dc (patch)
tree3513487f65c1a7df47996bd2852393aceaac1b8a /src/org.gluster.storage.management.console/src
parent92c52d8edf285945d31e446503fc742fde9dcc49 (diff)
Renamed projects / packages com.gluster.* to org.gluster.*
Diffstat (limited to 'src/org.gluster.storage.management.console/src')
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Activator.java83
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/AlertsManager.java216
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Application.java135
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationActionBarAdvisor.java102
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchAdvisor.java98
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchWindowAdvisor.java63
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/BrickTableLabelProvider.java85
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ConsoleConstants.java29
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/DeviceTableLabelProvider.java160
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/EntityGroupContentProvider.java45
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterDataModelManager.java1036
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterServerTableLabelProvider.java77
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ICommandIds.java33
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IEntityListener.java37
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IImageKeys.java97
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/NetworkInterfaceTableLabelProvider.java44
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Perspective.java36
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerDiskTableLabelProvider.java134
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerTableLabelProvider.java53
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TableLabelProviderAdapter.java58
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TasksTableLabelProvider.java71
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeLogTableLabelProvider.java41
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsContentProvider.java47
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsTableLabelProvider.java39
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeTableLabelProvider.java82
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractActionDelegate.java103
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractMonitoredActionDelegate.java56
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ActionConstants.java36
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddBrickAction.java64
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddServerAction.java124
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ChangePasswordAction.java23
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ClearTaskAction.java46
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CommitTaskAction.java72
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CreateVolumeAction.java53
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DeleteVolumeAction.java210
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DownloadVolumeLogsAction.java61
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/EditVolumeAction.java33
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ExportSshKeysAction.java61
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ForceStartVolumeAction.java71
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ImportSshKeysAction.java44
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateBrickAction.java69
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateVolumeAction.java33
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PauseTaskAction.java67
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PreferencesAction.java36
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RebalanceVolumeAction.java82
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RefreshDataAction.java43
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveBrickAction.java91
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveServerAction.java159
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResetVolumeOptionsAction.java62
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResumeTaskAction.java45
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ServerAdditionAction.java28
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StartVolumeAction.java171
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopTaskAction.java46
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopVolumeAction.java229
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/SupportAction.java48
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TerminalAction.java44
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TestPopupMenuAction.java63
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/VolumeLogRotateAction.java64
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickPage.java171
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickWizard.java96
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/BricksSelectionPage.java336
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ChangePasswordDialog.java284
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ClusterSelectionDialog.java474
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumePage1.java473
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumeWizard.java158
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/GlusterSupportDialog.java139
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/InitDiskDialog.java212
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/LoginDialog.java359
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickPage1.java302
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickWizard.java106
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/SelectDisksDialog.java113
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ServerAdditionDialog.java197
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/jobs/DataSyncJob.java68
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/AlertsPreferencePage.java38
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/ChartsPreferencePage.java65
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/GlusterPreferencePage.java90
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceConstants.java40
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceInitializer.java60
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/GlusterToolbarManager.java105
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/ToolbarManager.java35
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartUtil.java339
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartViewerComposite.java475
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/EntityViewerFilter.java78
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GUIHelper.java481
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterChartPalette.java479
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterLogger.java67
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ImageUtil.java52
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/TableViewerComparator.java73
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/validators/StringRequiredValidator.java61
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterAdapterFactory.java101
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterSummaryView.java469
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServerView.java90
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServersView.java83
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DisksView.java45
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerDisksView.java84
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerLogsView.java59
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerSummaryView.java544
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersSummaryView.java290
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersView.java78
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterViewsManager.java130
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationTreeLabelDecorator.java87
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationView.java161
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/TasksView.java39
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ViewsManager.java38
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeBricksView.java39
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeLogsView.java58
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeOptionsView.java36
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeSummaryView.java859
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeView.java90
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesSummaryView.java301
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesView.java80
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractDisksPage.java335
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableTreeViewerPage.java191
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableViewerPage.java263
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/BricksPage.java123
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DiskTreeContentProvider.java119
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DisksPage.java70
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/GlusterServersPage.java138
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionKeyEditingSupport.java120
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionValueEditingSupport.java110
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerDisksPage.java66
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerLogsPage.java199
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServersPage.java138
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/TasksPage.java151
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeLogsPage.java431
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeOptionsPage.java360
-rw-r--r--src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumesPage.java135
-rw-r--r--src/org.gluster.storage.management.console/src/test.xml1
128 files changed, 18075 insertions, 0 deletions
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Activator.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Activator.java
new file mode 100644
index 00000000..0edd74cf
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Activator.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.gluster.storage.management.console"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ public void editorOpened() {
+ System.err.println("Editor opened!");
+ }
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns an image descriptor for the image file at the given
+ * plug-in relative path
+ *
+ * @param path the path
+ * @return the image descriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/AlertsManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/AlertsManager.java
new file mode 100644
index 00000000..c44dea09
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/AlertsManager.java
@@ -0,0 +1,216 @@
+/**
+ * AlertsManager.java
+ *
+ * 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 org.gluster.storage.management.console;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Partition;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Alert.ALERT_TYPES;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class AlertsManager {
+ private List<Alert> alerts = new ArrayList<Alert>();
+ private Cluster cluster;
+
+ private Double CPU_USAGE_THRESHOLD;
+ private Double MEMORY_USAGE_THRESHOLD;
+ private Double DISK_SPACE_USAGE_THRESHOLD;
+
+ public AlertsManager(Cluster cluster) {
+ this.cluster = cluster;
+
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ CPU_USAGE_THRESHOLD = preferenceStore.getDouble(PreferenceConstants.P_SERVER_CPU_CRITICAL_THRESHOLD);
+ MEMORY_USAGE_THRESHOLD = preferenceStore.getDouble(PreferenceConstants.P_SERVER_MEMORY_USAGE_THRESHOLD);
+ DISK_SPACE_USAGE_THRESHOLD = preferenceStore.getDouble(PreferenceConstants.P_DISK_SPACE_USAGE_THRESHOLD);
+ }
+
+ public List<Alert> getAlerts() {
+ return alerts;
+ }
+
+ public Alert getAlert(String id) {
+ for (Alert alert : getAlerts()) {
+ if (alert.getId().equals(id)) {
+ return alert;
+ }
+ }
+ return null;
+ }
+
+ public void addAlert(Alert alert) {
+ alerts.add(alert);
+ }
+
+ public void addAlerts(List<Alert> alerts) {
+ this.alerts.addAll(alerts);
+ }
+
+ public void setAlerts(List<Alert> alerts) {
+ this.alerts = alerts;
+ }
+
+ public Boolean removeAlert(String id) {
+ for (int i = 0; i < alerts.size(); i++) {
+ if (alerts.get(i).getId().equals(id)) {
+ return (alerts.remove(i) != null);
+ }
+ }
+ return false;
+ }
+
+ public void clearAll() {
+ this.alerts.clear();
+ }
+
+ public void buildAlerts() {
+ clearAll();
+ addAlerts(getServerAlerts());
+ addAlerts(getVolumeAlerts());
+ }
+
+ private List<Alert> getServerAlerts() {
+ List<Alert> serverAlerts = new ArrayList<Alert>();
+ Alert offlineServerAlert = getOfflineServerAlerts();
+ if (offlineServerAlert != null) {
+ serverAlerts.add(offlineServerAlert); // Single alert for offline servers
+ }
+
+ for (GlusterServer server : cluster.getServers()) {
+ // To check off line servers
+ // if (server.getStatus() == SERVER_STATUS.OFFLINE) {
+ // serverAlerts.add(new Alert(ALERT_TYPES.OFFLINE_SERVERS_ALERT, server.getName(), "Server ["
+ // + server.getName() + "] is Offline"));
+ // continue; // If the server is Offline skip other Alert builds
+ // }
+
+ // To check High CPU usage
+ if (server.getCpuUsage() >= CPU_USAGE_THRESHOLD) {
+ serverAlerts.add(new Alert(ALERT_TYPES.CPU_USAGE_ALERT, server.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.CPU_USAGE_ALERT.ordinal()] + " ["
+ + NumberUtil.formatNumber(server.getCpuUsage()) + "] in server [" + server.getName()
+ + "]"));
+ }
+
+ // To check High Memory usage
+ Double memoryUtilized = server.getMemoryInUse() / server.getTotalMemory() * 100d;
+ if (memoryUtilized >= MEMORY_USAGE_THRESHOLD) {
+ serverAlerts.add(new Alert(ALERT_TYPES.MEMORY_USAGE_ALERT, server.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.MEMORY_USAGE_ALERT.ordinal()] + " ["
+ + NumberUtil.formatNumber(memoryUtilized) + "%] in server [" + server.getName()
+ + "]"));
+ }
+
+ // To Check low disk space
+ serverAlerts.addAll(getLowDiskAlerts(server));
+ }
+ return serverAlerts;
+ }
+
+ private Alert getOfflineServerAlerts() {
+ List<String> offlineServers = new ArrayList<String>();
+ for (GlusterServer server : cluster.getServers()) {
+ if (server.getStatus() == SERVER_STATUS.OFFLINE) {
+ offlineServers.add(server.getName());
+ }
+ }
+ if (offlineServers.size() > 0) {
+ return new Alert(ALERT_TYPES.OFFLINE_SERVERS_ALERT, "Server",
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_SERVERS_ALERT.ordinal()] + "(s) "
+ + offlineServers.toString());
+ }
+ return null;
+ }
+
+ private List<Alert> getLowDiskAlerts(GlusterServer server) {
+ List<Alert> diskAlerts = new ArrayList<Alert>();
+ boolean hasPartition;
+ Double deviceSpaceUsed;
+ for (Disk disk : server.getDisks()) {
+ hasPartition = false;
+ for (Partition partition : disk.getPartitions()) {
+ hasPartition = true;
+ deviceSpaceUsed = partition.getSpaceInUse() / partition.getSpace() * 100d;
+ if (deviceSpaceUsed >= DISK_SPACE_USAGE_THRESHOLD) {
+ diskAlerts.add(new Alert(ALERT_TYPES.DISK_USAGE_ALERT, partition.getQualifiedName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.DISK_USAGE_ALERT.ordinal()] + " ["
+ + NumberUtil.formatNumber(deviceSpaceUsed) + "% used] in disk ["
+ + partition.getQualifiedName() + "]"));
+ }
+ }
+ if (hasPartition) {
+ continue; // Do not check disk usage
+ }
+
+ // If it is disk
+ deviceSpaceUsed = disk.getSpaceInUse() / disk.getSpace() * 100d;
+ if (deviceSpaceUsed >= DISK_SPACE_USAGE_THRESHOLD) {
+ diskAlerts.add(new Alert(ALERT_TYPES.DISK_USAGE_ALERT, disk.getQualifiedName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.DISK_USAGE_ALERT.ordinal()] + " ["
+ + NumberUtil.formatNumber(deviceSpaceUsed) + "% used] in ["
+ + disk.getQualifiedName() + "]"));
+ }
+ }
+ return diskAlerts;
+ }
+
+ private List<Alert> getVolumeAlerts() {
+ List<Alert> volumeAlerts = new ArrayList<Alert>();
+ List<String> offlineBricks = new ArrayList<String>();
+
+ for (Volume volume : cluster.getVolumes()) {
+ if (volume.getStatus() == VOLUME_STATUS.OFFLINE) {
+ volumeAlerts.add(new Alert(ALERT_TYPES.OFFLINE_VOLUME_ALERT, volume.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_VOLUME_ALERT.ordinal()] + " [" + volume.getName()
+ + "]"));
+ continue;
+ }
+
+ // To check off line bricks
+ offlineBricks = new ArrayList<String>();
+ for (Brick brick : volume.getBricks()) {
+ if (brick.getStatus() == BRICK_STATUS.OFFLINE) {
+ offlineBricks.add(brick.getQualifiedName());
+ }
+ }
+ // One offline brick alert per volume
+ if (offlineBricks.size() > 0) {
+ volumeAlerts.add(new Alert(ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT, volume.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT.ordinal()] + " "
+ + offlineBricks.toString() + " in volume " + volume.getName()));
+ }
+ }
+ return volumeAlerts;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Application.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Application.java
new file mode 100644
index 00000000..f5a88479
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Application.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.gluster.storage.management.console.dialogs.LoginDialog;
+import org.gluster.storage.management.core.model.Entity;
+
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class Application implements IApplication {
+
+ public static final String PLUGIN_ID = "org.gluster.storage.management.console";
+ private static Application instance;
+ private List<IEntityListener> entityListeners = Collections.synchronizedList(new ArrayList<IEntityListener>());
+ private IStatusLineManager statusLineManager;
+
+ public Application() {
+ instance = this;
+ }
+
+ public static Application getApplication() {
+ return instance;
+ }
+
+ public IStatusLineManager getStatusLineManager() {
+ return statusLineManager;
+ }
+
+ public void setStatusLineManager(IStatusLineManager statusLineManager) {
+ this.statusLineManager = statusLineManager;
+ }
+
+ private boolean login() {
+ LoginDialog loginDialog = new LoginDialog(new Shell(Display.getDefault()));
+ return (loginDialog.open() == Window.OK);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
+ */
+ public Object start(IApplicationContext context) {
+ setSystemProperties();
+
+ Display display = PlatformUI.createDisplay();
+
+ final boolean[] loginSuccess = new boolean[1];
+ Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
+ public void run() {
+ loginSuccess[0] = login();
+ }
+ });
+
+ if (!loginSuccess[0]) {
+ return IApplication.EXIT_OK;
+ }
+ try {
+ int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+ if (returnCode == PlatformUI.RETURN_RESTART) {
+ return IApplication.EXIT_RESTART;
+ }
+
+ return IApplication.EXIT_OK;
+ } finally {
+ display.dispose();
+ }
+ }
+
+ private void setSystemProperties() {
+ // TODO: Trying this to avoid the webstart authentication dialog
+ // to be tested, and removed if this doesn't work.
+ System.setProperty("javaws.cfg.jauthenticator", "none");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.equinox.app.IApplication#stop()
+ */
+ public void stop() {
+ if (!PlatformUI.isWorkbenchRunning())
+ return;
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ final Display display = workbench.getDisplay();
+ display.syncExec(new Runnable() {
+ public void run() {
+ if (!display.isDisposed())
+ workbench.close();
+ }
+ });
+ }
+
+ public void addEntityListener(IEntityListener listener) {
+ entityListeners.add(listener);
+ }
+
+ public void entityChanged(Entity entity, String[] paremeters) {
+ for (IEntityListener listener : entityListeners) {
+ listener.entityChanged(entity, paremeters);
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationActionBarAdvisor.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationActionBarAdvisor.java
new file mode 100644
index 00000000..df608eea
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationActionBarAdvisor.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+/**
+ * An action bar advisor is responsible for creating, adding, and disposing of the actions added to a workbench window.
+ * Each window will be populated with new actions.
+ */
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+ private IWorkbenchWindow window;
+ /*
+ * Actions - important to allocate these only in makeActions, and then use them in the fill methods. This ensures
+ * that the actions aren't recreated when fillActionBars is called with FILL_PROXY.
+ */
+ private IWorkbenchAction exitAction;
+ private IWorkbenchAction aboutAction;
+ private IWorkbenchAction helpContentsAction;
+
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
+ super(configurer);
+ }
+
+ protected void makeActions(final IWorkbenchWindow window) {
+ this.window = window;
+ /*
+ * Creates the actions and registers them. Registering is needed to ensure that key bindings work. The
+ * corresponding commands keybindings are defined in the plugin.xml file. Registering also provides automatic
+ * disposal of the actions when the window is closed.
+ */
+ exitAction = ActionFactory.QUIT.create(window);
+ register(exitAction);
+
+ aboutAction = ActionFactory.ABOUT.create(window);
+ aboutAction.setText("&About");
+ aboutAction.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.HELP_16x16));
+ register(aboutAction);
+
+ helpContentsAction = ActionFactory.HELP_CONTENTS.create(window);
+ helpContentsAction.setText("&Management Console Help");
+ helpContentsAction.setAccelerator(SWT.F1);
+ //helpContentsAction.setImageDescriptor(newImage)
+ register(helpContentsAction);
+ }
+
+ protected void fillMenuBar(IMenuManager menuBar) {
+ // File
+ MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
+ fileMenu.add(new Separator());
+ fileMenu.add(exitAction);
+
+ // Help
+ MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP);
+ helpMenu.add(helpContentsAction);
+ helpMenu.add(aboutAction);
+
+ menuBar.add(fileMenu);
+ // Add a group marker indicating where action set menus will appear.
+ // All action sets from plugin.xml will get added here
+ menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ menuBar.add(helpMenu);
+ }
+
+ protected void fillCoolBar(ICoolBarManager coolBar) {
+ // All our actions are added to toolbar through the extension point org.eclipse.ui.actionSets
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchAdvisor.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchAdvisor.java
new file mode 100644
index 00000000..e0fa5539
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.application.IWorkbenchConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+import org.gluster.storage.management.console.jobs.DataSyncJob;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+
+
+/**
+ * This workbench advisor creates the window advisor, and specifies
+ * the perspective id for the initial window.
+ */
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+ private Job syncJob;
+ private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ private long JOB_INTERVAL = preferenceStore.getLong(PreferenceConstants.P_DATA_SYNC_INTERVAL) * 1000;
+ private IPropertyChangeListener propertyChangeListener;
+
+ public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
+ return new ApplicationWorkbenchWindowAdvisor(configurer);
+ }
+
+ public String getInitialWindowPerspectiveId() {
+ return Perspective.ID;
+ }
+
+ @Override
+ public void initialize(IWorkbenchConfigurer configurer) {
+ super.initialize(configurer);
+ configurer.setSaveAndRestore(false); // we don't need save/restore as of now
+
+ createPropertyChangeListener();
+ preferenceStore.addPropertyChangeListener(propertyChangeListener);
+ }
+
+ private void createPropertyChangeListener() {
+ propertyChangeListener = new IPropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if(event.getProperty().equals(PreferenceConstants.P_DATA_SYNC_INTERVAL)) {
+ JOB_INTERVAL = (Integer)event.getNewValue() * 1000L;
+ }
+ }
+ };
+ }
+
+ @Override
+ public void postStartup() {
+ super.postStartup();
+ setupBackgroundJobs();
+ }
+
+ private void setupBackgroundJobs() {
+ syncJob = new DataSyncJob("Retrieving Management Info");
+ syncJob.schedule(JOB_INTERVAL);
+ syncJob.addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(IJobChangeEvent event) {
+ super.done(event);
+
+ // job done. schedule again after the pre-defined interval
+ syncJob.schedule(JOB_INTERVAL);
+ }
+ });
+ }
+
+ @Override
+ public boolean preShutdown() {
+ return syncJob.cancel();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchWindowAdvisor.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchWindowAdvisor.java
new file mode 100644
index 00000000..41043b27
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+ private final static int DEFAULT_WIDTH = 1024;
+ private final static int DEFAULT_HEIGHT = 768;
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+
+ public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
+ super(configurer);
+ }
+
+ @Override
+ public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
+ return new ApplicationActionBarAdvisor(configurer);
+ }
+
+ @Override
+ public void preWindowOpen() {
+ super.preWindowOpen();
+
+ IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
+ configurer.setInitialSize(new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+ configurer.setShowCoolBar(true);
+ configurer.setShowStatusLine(true);
+ configurer.setShowMenuBar(true);
+ configurer.setShowProgressIndicator(true); // shows progress indicator in status bar
+ }
+
+ @Override
+ public void postWindowCreate() {
+ super.postWindowCreate();
+ guiHelper.centerShellInScreen(getWindowConfigurer().getWindow().getShell());
+ getWindowConfigurer().getWindow().getShell().setMaximized(true);
+ Application.getApplication().setStatusLineManager(
+ getWindowConfigurer().getActionBarConfigurer().getStatusLineManager());
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/BrickTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/BrickTableLabelProvider.java
new file mode 100644
index 00000000..80b4c812
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/BrickTableLabelProvider.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.BricksPage.BRICK_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.console.views.pages.DisksPage.DISK_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class BrickTableLabelProvider extends TableLabelProviderAdapter {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+
+ if (!(element instanceof Brick)) {
+ return null;
+ }
+
+ Brick brick = (Brick) element;
+ if (columnIndex == DISK_TABLE_COLUMN_INDICES.STATUS.ordinal()) {
+ BRICK_STATUS status = brick.getStatus();
+
+ switch(status) {
+ case ONLINE:
+ return guiHelper.getImage(IImageKeys.BRICK_ONLINE_16x16);
+ case OFFLINE:
+ return guiHelper.getImage(IImageKeys.BRICK_OFFLINE_16x16);
+ }
+ }
+ return null;
+ }
+
+ private String getDeviceFreeSpace(Device device) {
+ if (device != null && device.isReady() && device.getFreeSpace() != null) {
+ return NumberUtil.formatNumber((device.getFreeSpace() / 1024));
+ } else {
+ return "NA";
+ }
+ }
+
+ private String getDeviceCapacity(Device device) {
+ if (device != null && device.isReady() && device.getSpace() != null && device.getSpace() != 0.0) {
+ return NumberUtil.formatNumber((device.getSpace() / 1024));
+ } else {
+ return "NA";
+ }
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Brick)) {
+ return null;
+ }
+
+ Brick brick = (Brick) element;
+ Device device = GlusterDataModelManager.getInstance().getDeviceForBrickDir(brick);
+ return (columnIndex == BRICK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? brick.getServerName()
+ : columnIndex == BRICK_TABLE_COLUMN_INDICES.BRICK.ordinal() ? brick.getBrickDirectory()
+ : columnIndex == BRICK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal() ? getDeviceFreeSpace(device)
+ : columnIndex == BRICK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal() ? getDeviceCapacity(device)
+ : columnIndex == BRICK_TABLE_COLUMN_INDICES.STATUS.ordinal() ? brick.getStatusStr() : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ConsoleConstants.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ConsoleConstants.java
new file mode 100644
index 00000000..ced7f9e7
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ConsoleConstants.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+/**
+ *
+ */
+public class ConsoleConstants {
+ public static final String CONSOLE_TITLE = "Gluster Management Console";
+ public static final String TERMINAL_VIEW_ID = "org.eclipse.tm.terminal.view.TerminalView";
+ public static final String PROPERTY_AUTO_LOGIN_PASSWORD = "auto.login.password";
+ public static final String PROPERTY_AUTO_CLUSTER_NAME = "auto.cluster.name";
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/DeviceTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/DeviceTableLabelProvider.java
new file mode 100644
index 00000000..6b6f7669
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/DeviceTableLabelProvider.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Partition;
+import org.gluster.storage.management.core.model.Device.DEVICE_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class DeviceTableLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ public enum DEVICE_COLUMN_INDICES {
+ DISK, PARTITION, FREE_SPACE, SPACE_IN_USE, STATUS
+ };
+
+ FontRegistry registry = new FontRegistry();
+
+ public DeviceTableLabelProvider() {
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (!(element instanceof Device)) {
+ return null;
+ }
+
+ Device device = (Device) element;
+ if (columnIndex == DEVICE_COLUMN_INDICES.STATUS.ordinal()) {
+ DEVICE_STATUS status = device.getStatus();
+
+ if (status == null) {
+ if (element instanceof Partition) {
+ if (columnIndex == DEVICE_COLUMN_INDICES.STATUS.ordinal()) {
+ status = device.getStatus();
+ }
+ }
+ }
+
+ if (status == null) {
+ return null;
+ }
+
+ if(element instanceof Disk && ((Disk)element).hasPartitions()) {
+ // disk has partitions. so don't show status image at disk level.
+ return null;
+ }
+
+ switch (status) {
+ case INITIALIZED:
+ if(modelManager.isDeviceUsed(device)) {
+ return guiHelper.getImage(IImageKeys.DISK_IN_USE_16x16);
+ } else {
+ return guiHelper.getImage(IImageKeys.DISK_AVAILABLE_16x16);
+ }
+ case IO_ERROR:
+ return guiHelper.getImage(IImageKeys.IO_ERROR_16x16);
+ case UNINITIALIZED:
+ return guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED_16x16);
+ case INITIALIZING:
+ return guiHelper.getImage(IImageKeys.DISK_INITIALIZING_16x16);
+ default:
+ throw new GlusterRuntimeException("Invalid disk status [" + status + "]");
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getText(Object element) {
+ return super.getText(element);
+ }
+
+ private String getDeviceFreeSpace(Device device) {
+ if (device.hasErrors() || device.isUninitialized()) {
+ return "NA";
+ } else {
+ return NumberUtil.formatNumber((device.getFreeSpace() / 1024));
+ }
+ }
+
+ private String getTotalDeviceSpace(Device device) {
+ if (device.hasErrors() || device.isUninitialized()) {
+ return "NA";
+ } else {
+ return NumberUtil.formatNumber((device.getSpace() / 1024));
+ }
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+
+ if (element == null) {
+ return "";
+ }
+
+ Device device = (Device) element;
+ if (columnIndex == DEVICE_COLUMN_INDICES.DISK.ordinal()) {
+ // show value in "disk" column only if it's a disk
+ if (device instanceof Disk) {
+ return device.getQualifiedName();
+ } else {
+ return "";
+ }
+ }
+
+ if(element instanceof Disk && ((Disk)element).hasPartitions()) {
+ // disk has partitions. so don't show any other details
+ return "";
+ }
+
+ if (columnIndex == DEVICE_COLUMN_INDICES.FREE_SPACE.ordinal()) {
+ return "" + getDeviceFreeSpace(device);
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.SPACE_IN_USE.ordinal()) {
+ return "" + getTotalDeviceSpace(device);
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.PARTITION.ordinal()) {
+ if (device instanceof Partition) {
+ return device.getQualifiedName();
+ } else {
+ return "";
+ }
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.STATUS.ordinal()) {
+ if(device.isUninitialized()) {
+ return "";
+ }
+ if(modelManager.isDeviceUsed(device)) {
+ return "In Use";
+ } else {
+ return device.getStatusStr();
+ }
+ } else {
+ return "";
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/EntityGroupContentProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/EntityGroupContentProvider.java
new file mode 100644
index 00000000..ca83d520
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/EntityGroupContentProvider.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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.gluster.storage.management.core.model.EntityGroup;
+
+
+public class EntityGroupContentProvider<T> implements
+ IStructuredContentProvider {
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof EntityGroup) {
+ return ((EntityGroup) inputElement).getChildren().toArray();
+ }
+ return null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterDataModelManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterDataModelManager.java
new file mode 100644
index 00000000..94d3c59c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterDataModelManager.java
@@ -0,0 +1,1036 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.gluster.storage.management.client.DiscoveredServersClient;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterDataModel;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Partition;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeOptionInfo;
+import org.gluster.storage.management.core.model.Alert.ALERT_TYPES;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.model.Device.DEVICE_STATUS;
+import org.gluster.storage.management.core.model.Device.DEVICE_TYPE;
+import org.gluster.storage.management.core.model.Event.EVENT_TYPE;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+
+
+public class GlusterDataModelManager {
+ private static GlusterDataModelManager instance = new GlusterDataModelManager();
+ private GlusterDataModel model;
+ private String securityToken;
+ private List<ClusterListener> listeners = new ArrayList<ClusterListener>();
+ private List<VolumeOptionInfo> volumeOptionsInfo;
+ private String clusterName;
+ private static Boolean syncInProgress = false;
+ private static final GlusterLogger logger = GlusterLogger.getInstance();;
+
+ private GlusterDataModelManager() {
+ }
+
+ public String getSecurityToken() {
+ return securityToken;
+ }
+
+ public void setSecurityToken(String securityToken) {
+ this.securityToken = securityToken;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public GlusterDataModel getModel() {
+ return model;
+ }
+
+ public static GlusterDataModelManager getInstance() {
+ return instance;
+ }
+
+ public void initializeModel(String clusterName, IProgressMonitor monitor) {
+ setClusterName(clusterName);
+
+ model = fetchData(monitor);
+ }
+
+ private GlusterDataModel fetchData(IProgressMonitor monitor) {
+ GlusterDataModel model = fetchModel(monitor);
+
+ initializeAlerts(model.getCluster());
+ initializeVolumeOptionsInfo(model.getCluster());
+
+ return model;
+ }
+
+ public void refreshVolumeData(Volume oldVolume) {
+ VolumesClient volumeClient = new VolumesClient();
+ Volume newVolume = volumeClient.getVolume(oldVolume.getName());
+ if(!oldVolume.equals(newVolume)) {
+ volumeChanged(oldVolume, newVolume);
+ }
+ }
+
+ private boolean isCancelled(IProgressMonitor monitor) {
+ if(monitor.isCanceled()) {
+ monitor.setTaskName("Data sync cancelled!");
+ monitor.done();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public GlusterDataModel fetchModel(IProgressMonitor monitor) {
+ synchronized (syncInProgress) {
+ if(syncInProgress) {
+ logger.info("Previous data sync is still running. Skipping this one.");
+ return null;
+ }
+ syncInProgress = true;
+ }
+
+ try {
+ logger.info("Starting data sync");
+ GlusterDataModel model = new GlusterDataModel("Gluster Data Model");
+ Cluster cluster = new Cluster(clusterName, model);
+ model.addCluster(cluster);
+
+ monitor.beginTask("Data Sync", 6);
+
+ monitor.setTaskName("Syncing servers...");
+ initializeGlusterServers(cluster);
+ monitor.worked(1);
+ if(isCancelled(monitor)) {
+ return model;
+ }
+
+ monitor.setTaskName("Syncing volumes...");
+ initializeVolumes(cluster);
+ monitor.worked(1);
+ if(isCancelled(monitor)) {
+ return model;
+ }
+
+ monitor.setTaskName("Syncing discovered servers...");
+ initializeAutoDiscoveredServers(cluster);
+ monitor.worked(1);
+ if(isCancelled(monitor)) {
+ return model;
+ }
+
+ monitor.setTaskName("Syncing tasks...");
+ initializeTasks(cluster);
+ monitor.worked(1);
+ if(isCancelled(monitor)) {
+ return model;
+ }
+
+ monitor.setTaskName("Syncing aggregated CPU stats...");
+ initializeAggregatedCpuStats(cluster);
+ monitor.worked(1);
+ if(isCancelled(monitor)) {
+ return model;
+ }
+
+ monitor.setTaskName("Syncing aggregated Network stats...");
+ initializeAggregatedNetworkStats(cluster);
+ monitor.worked(1);
+
+ monitor.done();
+ return model;
+ } finally {
+ syncInProgress = false;
+ }
+ }
+
+ public void updateModel(GlusterDataModel model) {
+ updateVolumes(model);
+ updateGlusterServers(model);
+ updateDiscoveredServers(model);
+ updateTasks(model);
+ updateAlerts(model);
+ updateServerStatistics(model);
+ }
+
+ private void updateServerStatistics(GlusterDataModel newModel) {
+ model.getCluster().setAggregatedCpuStats(newModel.getCluster().getAggregatedCpuStats());
+ model.getCluster().setAggregatedNetworkStats(newModel.getCluster().getAggregatedNetworkStats());
+ for(ClusterListener listener : listeners) {
+ listener.aggregatedStatsChanged();
+ }
+ }
+
+ private void updateAlerts(GlusterDataModel newModel) {
+ model.getCluster().getAlerts().clear();
+
+ // generate alerts for "newModel"
+ initializeAlerts(newModel.getCluster());
+
+ // set the new alerts on "model"
+ model.getCluster().setAlerts(newModel.getCluster().getAlerts());
+
+ // fire event "alertsGenerated"
+ alertsGenerated();
+ }
+
+ private void updateTasks(GlusterDataModel newModel) {
+ List<TaskInfo> oldTasks = model.getCluster().getTaskInfoList();
+ List<TaskInfo> newTasks = newModel.getCluster().getTaskInfoList();
+
+ Set<TaskInfo> addedTasks = GlusterCoreUtil.getAddedEntities(oldTasks, newTasks, true);
+ for(TaskInfo task : addedTasks) {
+ addTask(task);
+ }
+
+ Set<TaskInfo> removedTasks = GlusterCoreUtil.getAddedEntities(newTasks, oldTasks, true);
+ for(TaskInfo task : removedTasks) {
+ removeTask(task);
+ }
+
+ Map<TaskInfo, TaskInfo> modifiedTasks = GlusterCoreUtil.getModifiedEntities(oldTasks, newTasks);
+ for(Entry<TaskInfo, TaskInfo> entry : modifiedTasks.entrySet()) {
+ TaskInfo modifiedTask = entry.getKey();
+ modifiedTask.copyFrom(entry.getValue());
+ updateTask(modifiedTask);
+ }
+ }
+
+ private void updateDiscoveredServers(GlusterDataModel newModel) {
+ List<Server> oldServers = model.getCluster().getAutoDiscoveredServers();
+ List<Server> newServers = newModel.getCluster().getAutoDiscoveredServers();
+
+ Set<Server> addedServers = GlusterCoreUtil.getAddedEntities(oldServers, newServers, true);
+ for (Server addedServer : addedServers) {
+ addDiscoveredServer(addedServer);
+ }
+
+ Set<Server> removedServers = GlusterCoreUtil.getAddedEntities(newServers, oldServers, true);
+ for (Server removedServer : removedServers) {
+ removeDiscoveredServer(removedServer);
+ }
+
+ Map<Server, Server> modifiedServers = GlusterCoreUtil.getModifiedEntities(oldServers, newServers);
+ for(Entry<Server, Server> entry : modifiedServers.entrySet()) {
+ discoveredServerChanged(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private void updateGlusterServers(GlusterDataModel newModel) {
+ List<GlusterServer> oldServers = model.getCluster().getServers();
+ List<GlusterServer> newServers = newModel.getCluster().getServers();
+
+ Set<GlusterServer> addedServers = GlusterCoreUtil.getAddedEntities(oldServers, newServers, true);
+ for (GlusterServer addedServer : addedServers) {
+ addGlusterServer(addedServer);
+ }
+
+ Set<GlusterServer> removedServers = GlusterCoreUtil.getAddedEntities(newServers, oldServers, true);
+ for (GlusterServer removedServer : removedServers) {
+ removeGlusterServer(removedServer);
+ }
+
+ Map<GlusterServer, GlusterServer> modifiedServers = GlusterCoreUtil.getModifiedEntities(oldServers, newServers);
+ for(Entry<GlusterServer, GlusterServer> entry : modifiedServers.entrySet()) {
+ glusterServerChanged(entry.getKey(), entry.getValue());
+ }
+ }
+
+ public void glusterServerChanged(GlusterServer oldServer, GlusterServer newServer) {
+ oldServer.copyFrom(newServer);
+ for (ClusterListener listener : listeners) {
+ listener.serverChanged(oldServer, new Event(EVENT_TYPE.GLUSTER_SERVER_CHANGED, newServer));
+ }
+
+ updateDisks(oldServer, oldServer.getDisks(), newServer.getDisks());
+ }
+
+ private void updateDisks(Server server, List<Disk> oldDisks, List<Disk> newDisks) {
+ Set<Disk> addedDisks = GlusterCoreUtil.getAddedEntities(oldDisks, newDisks, false);
+ addDisks(server, addedDisks);
+
+ Set<Disk> removedDisks = GlusterCoreUtil.getAddedEntities(newDisks, oldDisks, false);
+ removeDisks(server, removedDisks);
+
+ Map<Disk, Disk> modifiedDisks = GlusterCoreUtil.getModifiedEntities(oldDisks, newDisks);
+ disksChanged(server, modifiedDisks);
+ }
+
+ private void disksChanged(Server server, Map<Disk, Disk> modifiedDisks) {
+ if(modifiedDisks.size() == 0) {
+ return;
+ }
+
+ for (Entry<Disk, Disk> entry : modifiedDisks.entrySet()) {
+ entry.getKey().copyFrom(entry.getValue());
+ }
+ for (ClusterListener listener : listeners) {
+ if (server instanceof GlusterServer) {
+ listener.serverChanged((GlusterServer) server, new Event(EVENT_TYPE.DEVICES_CHANGED, modifiedDisks));
+ } else {
+ listener.discoveredServerChanged(server, new Event(EVENT_TYPE.DEVICES_CHANGED, modifiedDisks));
+ }
+ }
+ }
+
+ public void updateDeviceStatus(String serverName, String deviceName, DEVICE_STATUS status) {
+ GlusterServer server = model.getCluster().getServer(serverName);
+ Device device = getDeviceDetails(server, deviceName);
+ if (device != null) {
+ device.setStatus(status);
+ device.setType(DEVICE_TYPE.DATA);
+ for (ClusterListener listener : listeners) {
+ listener.serverChanged(server, new Event(EVENT_TYPE.DEVICES_CHANGED, device));
+ }
+ }
+ }
+
+ private Device getDeviceDetails(GlusterServer server, String deviceName) {
+ for (Disk disk : server.getDisks()) {
+ if (disk.hasPartitions()) {
+ for (Partition partition : disk.getPartitions()) {
+ if (partition.getName().equals(deviceName)) {
+ return partition;
+ }
+ }
+ } else {
+ if (disk.getName().equals(deviceName)) {
+ return (Device) disk;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void addDisks(Server server, Set<Disk> disks) {
+ if(disks.size() == 0) {
+ return;
+ }
+
+ server.addDisks(disks);
+ for (ClusterListener listener : listeners) {
+ if(server instanceof GlusterServer) {
+ listener.serverChanged((GlusterServer)server, new Event(EVENT_TYPE.DEVICES_ADDED, disks));
+ } else {
+ listener.discoveredServerChanged(server, new Event(EVENT_TYPE.DEVICES_ADDED, disks));
+ }
+ }
+ }
+
+ public void removeDisks(Server server, Set<Disk> disks) {
+ if(disks.size() == 0) {
+ return;
+ }
+
+ for(Disk disk : disks) {
+ server.removeDisk(disk);
+ }
+
+ for (ClusterListener listener : listeners) {
+ if(server instanceof GlusterServer) {
+ listener.serverChanged((GlusterServer)server, new Event(EVENT_TYPE.DEVICES_REMOVED, disks));
+ } else {
+ listener.discoveredServerChanged(server, new Event(EVENT_TYPE.DEVICES_REMOVED, disks));
+ }
+ }
+ }
+
+ private void updateVolumes(GlusterDataModel newModel) {
+ List<Volume> oldVolumes = model.getCluster().getVolumes();
+ List<Volume> newVolumes = newModel.getCluster().getVolumes();
+
+ Set<Volume> addedVolumes = GlusterCoreUtil.getAddedEntities(oldVolumes, newVolumes, false);
+ for (Volume addedVolume : addedVolumes) {
+ addVolume(addedVolume);
+ }
+
+ Set<Volume> removedVolumes = GlusterCoreUtil.getAddedEntities(newVolumes, oldVolumes, false);
+ for (Volume removedVolume : removedVolumes) {
+ deleteVolume(removedVolume);
+ }
+
+ Map<Volume, Volume> modifiedVolumes = GlusterCoreUtil.getModifiedEntities(oldVolumes, newVolumes);
+ for(Entry<Volume, Volume> entry : modifiedVolumes.entrySet()) {
+ volumeChanged(entry.getKey(), entry.getValue());
+ }
+ }
+
+ public void volumeChanged(Volume oldVolume, Volume newVolume) {
+ oldVolume.copyFrom(newVolume);
+
+ if (oldVolume.getStatus() != newVolume.getStatus()) {
+ updateVolumeStatusAlert(newVolume, newVolume.getStatus());
+ }
+
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(oldVolume, new Event(EVENT_TYPE.VOLUME_CHANGED, newVolume));
+ }
+ updateBricks(oldVolume, oldVolume.getBricks(), newVolume.getBricks());
+ }
+
+ private void updateBricks(Volume volume, List<Brick> oldBricks, List<Brick> newBricks) {
+ Set<Brick> addedBricks = GlusterCoreUtil.getAddedEntities(oldBricks, newBricks, false);
+ addBricks(volume, addedBricks);
+
+ Set<Brick> removedBricks = GlusterCoreUtil.getAddedEntities(newBricks, oldBricks, false);
+ removeBricks(volume, removedBricks);
+
+ Map<Brick, Brick> modifiedBricks = GlusterCoreUtil.getModifiedEntities(oldBricks, newBricks);
+ bricksChanged(volume, modifiedBricks);
+ }
+
+ public void bricksChanged(Volume volume, Map<Brick, Brick> modifiedBricks) {
+ if(modifiedBricks.size() == 0) {
+ return;
+ }
+
+ for(Entry<Brick, Brick> entry : modifiedBricks.entrySet()) {
+ entry.getKey().copyFrom(entry.getValue());
+ }
+
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.BRICKS_CHANGED, modifiedBricks));
+ }
+ }
+
+ private void initializeGlusterServers(Cluster cluster) {
+ cluster.setServers(new GlusterServersClient(cluster.getName()).getServers());
+ }
+
+ private void initializeAutoDiscoveredServers(Cluster cluster) {
+ cluster.setAutoDiscoveredServers(new DiscoveredServersClient(cluster.getName()).getDiscoveredServerDetails());
+ }
+
+ private void initializeVolumes(Cluster cluster) {
+ VolumesClient volumeClient = new VolumesClient(cluster.getName());
+ cluster.setVolumes(volumeClient.getAllVolumes());
+ }
+
+ private void initializeVolumeOptionsInfo(Cluster cluster) {
+ if(cluster.getServers().isEmpty()) {
+ // cluster is empty. we won't be able to fetch the volume options information.
+ return;
+ }
+ this.volumeOptionsInfo = new VolumesClient(clusterName).getVolumeOptionsInfo();
+ }
+
+ private void initializeTasks(Cluster cluster) {
+ List<TaskInfo> taskInfoList = new TasksClient(cluster.getName()).getAllTasks();
+ //List<TaskInfo> taskInfoList = getDummyTasks();
+ cluster.setTaskInfoList(taskInfoList);
+ }
+
+ public void initializeAggregatedCpuStats(Cluster cluster) {
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD);
+
+ cluster.setAggregatedCpuStats(new GlusterServersClient().getAggregatedCpuStats(cpuStatsPeriod));
+ }
+
+ public void initializeAggregatedNetworkStats(Cluster cluster) {
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD);
+
+ cluster.setAggregatedNetworkStats(new GlusterServersClient().getAggregatedNetworkStats(networkStatsPeriod));
+ }
+
+ private List<TaskInfo> getDummyTasks() {
+ List<TaskInfo> taskInfoList = new ArrayList<TaskInfo>();
+
+ // Task #1
+ TaskInfo taskInfo = new TaskInfo();
+ taskInfo.setType(TASK_TYPE.BRICK_MIGRATE);
+ taskInfo.setName("Migrate Brick-music");
+ taskInfo.setPauseSupported(true);
+ taskInfo.setStopSupported(true);
+ taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_PAUSE, "")));
+
+ taskInfo.getStatus().setMessage("Paused");
+ taskInfo.setDescription("Migrate Brick on volume [Movies] from /export/adb/music to /export/sdc/music.");
+ taskInfoList.add(taskInfo);
+
+ // Task #2
+ taskInfo = new TaskInfo();
+ taskInfo.setType(TASK_TYPE.DISK_FORMAT);
+ taskInfo.setName("Initialize disk [KVM-GVSA1:sdc]");
+ taskInfo.setPauseSupported(false);
+ taskInfo.setStopSupported(false);
+ taskInfo.setStatus( new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, "")));
+ taskInfo.getStatus().setMessage("Format completed 80% ...");
+ taskInfo.setDescription("Formatting disk [KVM-GVSA1:sdc]");
+ taskInfoList.add(taskInfo);
+
+ // Task #2
+ taskInfo = new TaskInfo();
+ taskInfo.setType(TASK_TYPE.VOLUME_REBALANCE);
+ taskInfo.setName("Rebalance volume [songs]");
+ taskInfo.setPauseSupported(false);
+ taskInfo.setStopSupported(false);
+ taskInfo.setStatus( new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, "")));
+ taskInfo.getStatus().setMessage("Rebalance step1: layout fix in progress");
+ taskInfo.setDescription("Rebalance volume [songs]");
+ taskInfoList.add(taskInfo);
+
+ return taskInfoList;
+ }
+
+ private List<Alert> getDummyAlerts(Cluster cluster) {
+ List<Alert> alerts = new ArrayList<Alert>();
+ for (Server server : cluster.getServers()) {
+ if (alerts.size() == 0) {
+ alerts.add(new Alert(ALERT_TYPES.CPU_USAGE_ALERT, server.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.CPU_USAGE_ALERT.ordinal()] + " [93.42 %] in "
+ + server.getName()));
+ continue;
+ }
+
+ if (alerts.size() == 1) {
+ alerts.add(new Alert(ALERT_TYPES.MEMORY_USAGE_ALERT, server.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.MEMORY_USAGE_ALERT.ordinal()] + " [91.83 %] in "
+ + server.getName()));
+ continue;
+ }
+
+ if (alerts.size() == 2) {
+ alerts.add(new Alert(ALERT_TYPES.OFFLINE_SERVERS_ALERT, server.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_SERVERS_ALERT.ordinal()] + " " + server.getName()));
+ continue;
+ }
+
+ if (alerts.size() == 3) {
+ alerts.add(new Alert(ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT, "songs",
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT.ordinal()]
+ + " [KVM-GVSA4:/export/hdb4/songs] in volume [songs]"));
+ continue;
+ }
+ }
+ return alerts;
+ }
+
+ public void initializeAlerts(Cluster cluster) {
+ AlertsManager alertsManager = new AlertsManager(cluster);
+ alertsManager.buildAlerts();
+ cluster.setAlerts( alertsManager.getAlerts() );
+ //cluster.setAlerts( getDummyAlerts(cluster) );
+ }
+
+ public Volume addVolume(List<Volume> volumes, String name, Cluster cluster, VOLUME_TYPE volumeType,
+ TRANSPORT_TYPE transportType, VOLUME_STATUS status) {
+ Volume volume = new Volume(name, cluster, volumeType, transportType, status);
+ volumes.add(volume);
+
+ return volume;
+ }
+
+// private Device getDevice(String serverName, String deviceName) {
+// List<Device> allDevices = getReadyDevicesOfAllServers();
+// for (Device device : allDevices) {
+// if (device.getServerName().equals(serverName) && device.getName().equals(deviceName)) {
+// return device;
+// }
+// }
+// return null;
+// }
+
+ /*
+ * @param diskName (sda)
+ *
+ * @return The device object for given device name
+ */
+ public Device getDeviceDetails(String deviceName) {
+ List<Device> allDevices = getReadyDevicesOfAllServers();
+ for (Device device : allDevices) {
+ if (device.getName().equals(deviceName)) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+
+ public Device getDeviceForBrickDir(Brick brick) {
+ Device brickDevice = null;
+ for (Device device : getReadyDevicesOfServer(brick.getServerName(), new ArrayList<Device>())) {
+ if (brick.getBrickDirectory().startsWith( device.getMountPoint() )) {
+ if (brickDevice == null || device.getMountPoint().length() > brickDevice.getMountPoint().length()) {
+ brickDevice = device;
+ }
+ }
+ }
+ return brickDevice;
+ }
+
+ public List<Device> getDevicesOfVolume(Volume volume) {
+ Device device = null;
+ List<Device> volumeDevices = new ArrayList<Device>();
+ for (Brick brick : volume.getBricks()) {
+ // device = getDevice(brick.getServerName(), brick.getDeviceName());
+ device = getDeviceForBrickDir(brick);
+ if (device != null) {
+ volumeDevices.add(device);
+ }
+ }
+ return volumeDevices;
+ }
+
+ public List<Device> getReadyDevicesOfAllServers() {
+ return getReadyDevicesOfAllServersExcluding(new ArrayList<Device>());
+ }
+
+ public List<Device> getReadyDevicesOfAllServersExcluding(List<Device> excludeDevices) {
+ List<Device> devices = new ArrayList<Device>();
+
+ for (Server server : model.getCluster().getServers()) {
+ devices.addAll( getReadyDevicesOfServer(server.getName(), excludeDevices) );
+ }
+ return devices;
+ }
+
+ public List<Device> getReadyDevicesOfServer(String serverName, List<Device> excludeDevices) {
+ List<Device> devices = new ArrayList<Device>();
+ GlusterServer server = model.getCluster().getServer(serverName);
+ if (server == null || !server.isOnline()) {
+ return devices;
+ }
+ for (Disk disk : server.getDisks()) {
+ if (disk.hasPartitions()) {
+ for (Partition partition : disk.getPartitions()) {
+ if (partition.isReady() && !excludeDevices.contains(partition)) {
+ devices.add(partition);
+ }
+ }
+ } else if (disk.isReady() && !excludeDevices.contains(disk)) {
+ devices.add(disk);
+ }
+ }
+ return devices;
+ }
+
+ public void addClusterListener(ClusterListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeClusterListener(ClusterListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void addGlusterServer(GlusterServer server) {
+ Cluster cluster = model.getCluster();
+ cluster.addServer(server);
+
+ for (ClusterListener listener : listeners) {
+ listener.serverAdded(server);
+ }
+
+ removeDiscoveredServer(server.getName());
+ }
+
+ public void addDiscoveredServer(Server server) {
+ Cluster cluster = model.getCluster();
+ cluster.addDiscoveredServer(server);
+
+ for (ClusterListener listener : listeners) {
+ listener.discoveredServerAdded(server);
+ }
+ }
+
+ public void discoveredServerChanged(Server oldServer, Server newServer) {
+ oldServer.copyFrom(newServer);
+ for (ClusterListener listener : listeners) {
+ listener.discoveredServerChanged(oldServer, new Event(EVENT_TYPE.DISCOVERED_SERVER_CHANGED, newServer));
+ }
+ updateDisks(oldServer, oldServer.getDisks(), newServer.getDisks());
+ }
+
+ public void removeDiscoveredServer(String serverName) {
+ Cluster cluster = model.getCluster();
+ // TODO: Move auto-discovered servers outside the cluster
+ for(Server server : cluster.getAutoDiscoveredServers()) {
+ if(server.getName().toUpperCase().equals(serverName.toUpperCase())) {
+ removeDiscoveredServer(server);
+ return;
+ }
+ }
+ }
+
+ public void removeDiscoveredServer(Server server) {
+ Cluster cluster = model.getCluster();
+ cluster.removeDiscoveredServer(server);
+
+ for (ClusterListener listener : listeners) {
+ listener.discoveredServerRemoved(server);
+ }
+ }
+
+ public void removeGlusterServer(GlusterServer server) {
+ Cluster cluster = model.getCluster();
+ cluster.removeServer(server);
+
+ // can't use an iterator here. The method AbstractList.Itr#next checks for concurrent modification.
+ // Since listeners can end up creating new views, which add themselves as listeners, the listeners
+ // list can be concurrently modified which can result in an exception while using iterator.
+ // Hence we use List#get instead of the iterator
+ for(int i = 0; i < listeners.size(); i++) {
+ ClusterListener listener = listeners.get(i);
+ listener.serverRemoved(server);
+ }
+
+ // add it to discovered servers list if it is online server
+ if (server.isOnline()) {
+ Server removedServer = new Server();
+ removedServer.copyFrom(server);
+ removedServer.addDisks(server.getDisks());
+ addDiscoveredServer(removedServer);
+ }
+ }
+
+ public void deleteVolume(Volume volume) {
+ Cluster cluster = model.getCluster();
+ cluster.deleteVolume(volume);
+
+ // can't use an iterator here. The method AbstractList.Itr#next checks for concurrent modification.
+ // Since listeners can end up creating new views, which add themselves as listeners, the listeners
+ // list can be concurrently modified which can result in an exception while using iterator.
+ // Hence we use List#get instead of the iterator
+ for(int i = 0; i < listeners.size(); i++) {
+ ClusterListener listener = listeners.get(i);
+ listener.volumeDeleted(volume);
+ }
+ }
+
+ public void updateVolumeStatus(Volume volume, VOLUME_STATUS newStatus) {
+ volume.setStatus(newStatus);
+ updateVolumeStatusAlert(volume, newStatus);
+
+ if(newStatus == VOLUME_STATUS.OFFLINE) {
+ // mark as bricks also as offline
+ for(Brick brick : volume.getBricks()) {
+ brick.setStatus(BRICK_STATUS.OFFLINE);
+ }
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.BRICKS_CHANGED, volume.getBricks()));
+ }
+ } else {
+ Volume newVolume = new VolumesClient().getVolume(volume.getName()); //Getting latest brick info
+ updateBricks(volume, volume.getBricks(), newVolume.getBricks());
+ }
+
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.VOLUME_STATUS_CHANGED, newStatus));
+ }
+ }
+
+ private void updateVolumeStatusAlert(Volume volume, VOLUME_STATUS newStatus) {
+ Alert alert = null;
+ if (newStatus == VOLUME_STATUS.OFFLINE) {
+ alert = createOfflineVolumeAlert(volume);
+ for (ClusterListener listener : listeners) {
+ listener.alertCreated(alert);
+ }
+ } else {
+ alert = removeOfflineVolumeAlert(volume);
+ for (ClusterListener listener : listeners) {
+ listener.alertRemoved(alert);
+ }
+ }
+ }
+
+ private Alert createOfflineVolumeAlert(Volume volume) {
+ Alert alert = new Alert(ALERT_TYPES.OFFLINE_VOLUME_ALERT, volume.getName(),
+ Alert.ALERT_TYPE_STR[ALERT_TYPES.OFFLINE_VOLUME_ALERT.ordinal()] + " [" + volume.getName() + "]");
+ getModel().getCluster().addAlert(alert);
+ return alert;
+ }
+
+ private Alert removeOfflineVolumeAlert(Volume volume) {
+ List<Alert> clusterAlerts = getModel().getCluster().getAlerts();
+ Alert removedAlert = null;
+ for (Alert alert : clusterAlerts) {
+ if (alert.getType().equals(ALERT_TYPES.OFFLINE_VOLUME_ALERT)
+ && alert.getReference().equals(volume.getName())) {
+ removedAlert = alert;
+ clusterAlerts.remove(alert);
+ break;
+ }
+ }
+ return removedAlert;
+ }
+
+ public void resetVolumeOptions(Volume volume) {
+ volume.getOptions().clear();
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.VOLUME_OPTIONS_RESET, null));
+ }
+ }
+
+ public void addBricks(Volume volume, Set<Brick> bricks) {
+ if(bricks.size() == 0) {
+ return;
+ }
+
+ volume.addBricks(bricks);
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.BRICKS_ADDED, bricks));
+ }
+ updateVolumeTypeByBricks(volume);
+ }
+
+ public void removeBricks(Volume volume, Set<Brick> bricks) {
+ if(bricks.size() == 0) {
+ return;
+ }
+
+ // Remove the bricks from the volume object
+ for (Brick brick : bricks) {
+ volume.removeBrick(brick);
+ }
+
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.BRICKS_REMOVED, bricks));
+ }
+ updateVolumeTypeByBricks(volume);
+ }
+
+ private void updateVolumeTypeByBricks(Volume volume) {
+ VOLUME_TYPE volumeType = volume.getVolumeType();
+ if (volumeType.equals(VOLUME_TYPE.REPLICATE) || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_REPLICATE)) {
+ if (volume.getBricks().size() > volume.getReplicaCount()) {
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_REPLICATE);
+ } else {
+ volume.setVolumeType(VOLUME_TYPE.REPLICATE);
+ }
+ } else if (volumeType.equals(VOLUME_TYPE.STRIPE) || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_STRIPE)) {
+ if (volume.getBricks().size() > volume.getStripeCount()) {
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_STRIPE);
+ } else {
+ volume.setVolumeType(VOLUME_TYPE.STRIPE);
+ }
+ }
+ }
+
+ public void setVolumeOption(Volume volume, String optionKey, String optionValue) {
+ volume.setOption(optionKey, optionValue);
+ for (ClusterListener listener : listeners) {
+ listener.volumeChanged(volume, new Event(EVENT_TYPE.VOLUME_OPTION_SET, optionKey));
+ }
+ }
+
+ public void addVolume(Volume volume) {
+ Cluster cluster = model.getCluster();
+ cluster.addVolume(volume);
+
+ for (ClusterListener listener : listeners) {
+ listener.volumeCreated(volume);
+ }
+ }
+
+ public void addTask(TaskInfo taskInfo) {
+ Cluster cluster = model.getCluster();
+ // To avoid duplicate task, Remove if already exist
+ TaskInfo existingTaskInfo = getTask(taskInfo.getName());
+ if (getTask(taskInfo.getName()) != null) {
+ removeTask(existingTaskInfo);
+ }
+ cluster.addTaskInfo(taskInfo);
+ for (ClusterListener listener : listeners) {
+ listener.taskAdded(taskInfo);
+ }
+ }
+
+ public TaskInfo getTask(String taskId) {
+ for (TaskInfo taskInfo: model.getCluster().getTaskInfoList()) {
+ if (taskInfo.getName().equals(taskId)) {
+ return taskInfo;
+ }
+ }
+ return null;
+ }
+
+ public TaskInfo getTaskByReference(String reference) {
+ for (TaskInfo taskInfo: model.getCluster().getTaskInfoList()) {
+ if (taskInfo.getReference().equals(reference)) {
+ return taskInfo;
+ }
+ }
+ return null;
+ }
+
+ // Updating the Task
+ public void updateTask(TaskInfo taskInfo) {
+ for (ClusterListener listener : listeners) {
+ listener.taskUpdated(taskInfo);
+ }
+ }
+
+ public void removeTask(TaskInfo taskInfo) {
+ model.getCluster().removeTaskInfo(taskInfo);
+ for (ClusterListener listener : listeners) {
+ listener.taskRemoved(taskInfo);
+ }
+ }
+
+ public void alertsGenerated() {
+ for (ClusterListener listener : listeners) {
+ listener.alertsGenerated();
+ }
+ }
+
+ public List<VolumeOptionInfo> getVolumeOptionsInfo() {
+ if(volumeOptionsInfo == null || volumeOptionsInfo.isEmpty()) {
+ initializeVolumeOptionsInfo(getModel().getCluster());
+ }
+ return volumeOptionsInfo;
+ }
+
+ public VolumeOptionInfo getVolumeOptionInfo(String optionKey) {
+ for (VolumeOptionInfo info : volumeOptionsInfo) {
+ if (info.getName().equals(optionKey)) {
+ return info;
+ }
+ }
+ throw new GlusterRuntimeException("Invalid option key [" + optionKey
+ + "] passed to GlusterDataModelManager#getVolumeOptionInfo");
+ }
+
+ public String getVolumeOptionDefaultValue(String optionKey) {
+ return getVolumeOptionInfo(optionKey).getDefaultValue();
+ }
+
+ public String getVolumeOptionDesc(String optionKey) {
+ return getVolumeOptionInfo(optionKey).getDescription();
+ }
+
+ public void setAccessControlList(Volume volume, String accessControlList) {
+ setVolumeOption(volume, Volume.OPTION_AUTH_ALLOW, accessControlList);
+ }
+
+ public void setNfsEnabled(Volume volume, boolean enabled) {
+ setVolumeOption(volume, Volume.OPTION_NFS_DISABLE, (enabled) ? GlusterConstants.OFF : GlusterConstants.ON);
+ }
+
+ public void setCifsConfig(Volume volume, boolean enabled, List<String> cifsUsers) {
+ if (enabled) {
+ volume.enableCifs();
+ volume.setCifsUsers(cifsUsers);
+ } else {
+ volume.disableCifs();
+ }
+ }
+
+ public Server getGlusterServer(String serverName) {
+ for (Server server : model.getCluster().getServers()) {
+ if (server.getName().equalsIgnoreCase(serverName)) {
+ return server;
+ }
+ }
+ return null;
+ }
+
+ private Boolean isDeviceUsed(Volume volume, Device device) {
+ Device brickDevice = null;
+ for (Brick brick : volume.getBricks()) {
+ brickDevice = getDeviceForBrickDir(brick);
+ if (brickDevice != null && device.getName().equals(brickDevice.getName())
+ && device.getServerName().equalsIgnoreCase(brick.getServerName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isDeviceUsed(Device device) {
+ if (device.getStatus() == DEVICE_STATUS.INITIALIZED) {
+ for (Volume volume : model.getCluster().getVolumes()) {
+ if (isDeviceUsed(volume, device)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public List<String> getVolumesOfServer(String serverName) {
+ List<String> volumeNames = new ArrayList<String>();
+ Cluster cluster = model.getCluster();
+ for (Volume volume : cluster.getVolumes()) {
+ for (Brick brick : volume.getBricks()) {
+ if (serverName.equalsIgnoreCase(brick.getServerName())) {
+ volumeNames.add(volume.getName());
+ break;
+ }
+ }
+ }
+ return volumeNames;
+ }
+
+ public List<String> getOfflineServers() {
+ List<String> offlineServers = new ArrayList<String>();
+ for(GlusterServer server : model.getCluster().getServers()) {
+ if (!server.isOnline()) {
+ offlineServers.add(server.getName());
+ }
+ }
+ return offlineServers;
+ }
+
+ public List<String> getCifsEnabledVolumeNames(List<Volume> selectedVolumes) {
+ List<String> cifsVolumes = new ArrayList<String>();
+ for(Volume volume : selectedVolumes) {
+ if (volume.isCifsEnable()) {
+ cifsVolumes.add(volume.getName());
+ }
+ }
+ return cifsVolumes;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterServerTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterServerTableLabelProvider.java
new file mode 100644
index 00000000..3ea52446
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/GlusterServerTableLabelProvider.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.GlusterServersPage.GLUSTER_SERVER_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class GlusterServerTableLabelProvider extends TableLabelProviderAdapter {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (!(element instanceof GlusterServer)) {
+ return null;
+ }
+
+ GlusterServer server = (GlusterServer) element;
+ if(columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS.ordinal()) {
+ SERVER_STATUS status = server.getStatus();
+ if(status == SERVER_STATUS.ONLINE) {
+ return guiHelper.getImage(IImageKeys.STATUS_ONLINE_16x16);
+ } else {
+ return guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof GlusterServer)) {
+ return null;
+ }
+
+ GlusterServer server = (GlusterServer) element;
+
+ if (server.getStatus() == SERVER_STATUS.OFFLINE
+ && columnIndex != GLUSTER_SERVER_TABLE_COLUMN_INDICES.NAME.ordinal()
+ && columnIndex != GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS.ordinal()) {
+ return "NA";
+ }
+
+ return (columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.NAME.ordinal() ? server.getName()
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS.ordinal() ? server.getStatusStr()
+ // : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.PREFERRED_NETWORK.ordinal() ? server.getPreferredNetworkInterface().getName()
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.NUM_OF_CPUS.ordinal() ? "" + server.getNumOfCPUs()
+ //: columnIndex == SERVER_DISK_TABLE_COLUMN_INDICES.CPU_USAGE.ordinal() ? "" + server.getCpuUsage()
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_MEMORY.ordinal() ? "" + NumberUtil.formatNumber((server.getTotalMemory() / 1024))
+ //: columnIndex == SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE.ordinal() ? "" + server.getMemoryInUse()
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_FREE_SPACE.ordinal() ? NumberUtil.formatNumber((server.getFreeDiskSpace() / 1024))
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.IP_ADDRESSES.ordinal() ? server.getIpAddressesAsString()
+ : columnIndex == GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE.ordinal() ? NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024))
+ : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ICommandIds.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ICommandIds.java
new file mode 100644
index 00000000..c7772a03
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ICommandIds.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+/**
+ * Interface defining the application's command IDs.
+ * Key bindings can be defined for specific commands.
+ * To associate an action with a command, use IAction.setActionDefinitionId(commandId).
+ *
+ * @see org.eclipse.jface.action.IAction#setActionDefinitionId(String)
+ */
+public interface ICommandIds {
+
+ public static final String CMD_OPEN = "org.gluster.storage.management.console.open";
+ public static final String CMD_OPEN_MESSAGE = "org.gluster.storage.management.console.openMessage";
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IEntityListener.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IEntityListener.java
new file mode 100644
index 00000000..e9e837ba
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IEntityListener.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.gluster.storage.management.core.model.Entity;
+
+/**
+ * Any class that is interested in changes to entities in application scope should implement this interface and register
+ * with the application using {@link Application#addEntityListener(IEntityListener)}
+ *
+ * @author root
+ *
+ */
+public interface IEntityListener {
+ /**
+ * This method is called whenever any attribute of an entity in application scope changes
+ * @param entity Entity that has changed
+ * @param paremeters List of attribute names that have changed. This can be null.
+ */
+ public void entityChanged(Entity entity, String[] paremeters);
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IImageKeys.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IImageKeys.java
new file mode 100644
index 00000000..eba97ccc
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/IImageKeys.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+public interface IImageKeys {
+
+
+ public static final String CLUSTER_16x16 = "icons/tango/16x16/cluster.png";
+
+ public static final String VOLUMES_16x16 = "icons/tango/16x16/volumes.png";
+ public static final String VOLUME_16x16 = "icons/tango/16x16/volume.png";
+ public static final String CREATE_VOLUME_32x32 = "icons/tango/32x32/create-volume.png";
+ public static final String START_VOLUME_32x32 = "icons/tango/32x32/start-volume.png";
+ public static final String STOP_VOLUME_32x32 = "icons/tango/32x32/stop-volume.png";
+ public static final String RESET_VOLUME_OPTIONS_32x32 = "icons/tango/32x32/reset-volume-option.png";
+ public static final String VOLUME_OPTIONS_16x16 = "icons/tango/16x16/volume-options.png";
+ public static final String CREATE_VOLUME_48x48 = "icons/tango/48x48/create-volume.png";
+ public static final String REMOVE_VOLUME_32x32 = "icons/tango/32x32/remove-volume.png";
+ public static final String VOLUME_REBALANCE_32x32 = "icons/tango/32x32/volume-rebalance.png";
+ public static final String VOLUME_REBALANCE_22x22 = "icons/tango/22x22/volume-rebalance.png";
+ public static final String BRICK_MIGRATE_32x32 = "icons/tango/32x32/migrate-brick.png";
+ public static final String BRICK_MIGRATE_22x22 = "icons/tango/22x22/migrate-brick.png";
+ public static final String ADD_BRICK_32x32 = "icons/tango/32x32/add-brick.png";
+ public static final String REMOVE_BRICK_32x32 = "icons/tango/32x32/remove-brick.png";
+ public static final String BRICK_OFFLINE_22x22 = "icons/tango/22x22/offline-brick.png";
+ public static final String BRICKS_16x16 = "icons/tango/16x16/bricks.png";
+ public static final String BRICK_ONLINE_16x16 = "icons/tango/16x16/online-brick.png";
+ public static final String BRICK_OFFLINE_16x16 = "icons/tango/16x16/offline-brick.png";
+ public static final String VOLUME_OFFLINE_22x22 = "icons/tango/22x22/offline-volume.png";
+
+ public static final String SERVERS_16x16 = "icons/tango/16x16/servers.png";
+ public static final String SERVER_16x16 = "icons/tango/16x16/server.png";
+ public static final String SERVER_WARNING_22x22 = "icons/tango/22x22/server-warning.png";
+ public static final String MEMORY_USAGE_ALERT_22x22 = "icons/tango/22x22/high-memory-usage.png";
+ public static final String SERVER_OFFLINE_22x22 = "icons/tango/22x22/offline-server.png";
+ public static final String ADD_SERVER_32x32 = "icons/tango/32x32/add-server.png";
+ public static final String ADD_SERVER_48x48 = "icons/tango/48x48/add-server.png";
+ public static final String REMOVE_SERVER_32x32 = "icons/tango/32x32/remove-server.png";
+
+ public static final String DISK_16x16 = "icons/tango/16x16/disk.png";
+ public static final String DISKS_16x16 = "icons/tango/16x16/disk.png";
+ public static final String DISK_UNINITIALIZED_16x16 = "icons/tango/16x16/disk-uninitialized.png";
+ public static final String IO_ERROR_16x16 = "icons/tango/16x16/disk-error.png";
+ public static final String DISK_AVAILABLE_16x16 = "icons/tango/16x16/disk-available.png";
+ public static final String DISK_INITIALIZING_16x16 = "icons/tango/16x16/disk-initialisation.png";
+ public static final String DISK_INITIALIZING_22x22 = "icons/tango/22x22/disk-initialisation.png";
+ public static final String DISK_IN_USE_16x16 = "icons/tango/16x16/disk-inuse.png";
+ public static final String LOW_DISK_SPACE_22x22 = "icons/tango/22x22/low-diskspace.png";
+
+ public static final String STATUS_OFFLINE_16x16 = "icons/tango/16x16/status-offline.png";
+ public static final String STATUS_ONLINE_16x16 = "icons/tango/16x16/status-online.png";
+
+ public static final String HELP_16x16 = "icons/tango/16x16/question.png";
+ public static final String SEARCH_22x22 = "icons/tango/22x22/system-search.png";
+ public static final String ARROW_UP_16x16 = "icons/tango/16x16/arrow-up.png";
+ public static final String ARROW_DOWN_16x16 = "icons/tango/16x16/arrow-down.png";
+
+ public static final String DOWNLOAD_LOG_32x32 = "icons/tango/32x32/download-log.png";
+
+
+ public static final String PAUSE_TASK_32x32 = "icons/tango/32x32/pause.png";
+ public static final String RESUME_TASK_32x32 = "icons/tango/32x32/start.png";
+ public static final String STOP_TASK_32x32 = "icons/tango/32x32/stop.png";
+ public static final String CLEAR_TASK_32x32 = "icons/tango/32x32/clear-task.png";
+ public static final String COMMIT_TASK_32x32 = "icons/tango/32x32/commit-task.png";
+ public static final String PAUSE_TASK_16x16 = "icons/tango/16x16/pause.png";
+ public static final String RESUME_TASK_16x16 = "icons/tango/16x16/start.png";
+ public static final String STOP_TASK_16x16 = "icons/tango/16x16/stop.png";
+ public static final String CLEAR_TASK_16x16 = "icons/tango/16x16/close_task.png";
+ public static final String COMPLETED_TASK_16x16 = "icons/tango/16x16/task-completed.png";
+
+ public static final String OVERLAY_OFFLINE_8x8 = "icons/tango/8x8/offline.png";
+ public static final String OVERLAY_ONLINE_8x8 = "icons/tango/8x8/online.png";
+ public static final String OVERLAY_STAR_8x8 = "icons/tango/8x8/star.png";
+
+ public static final String SPLASH_IMAGE = "splash.bmp";
+ public static final String DIALOG_SPLASH_IMAGE = "images/splash-dialog.bmp";
+
+ public static final String GAUGE_SMALL = "images/gauge_small.png";
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/NetworkInterfaceTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/NetworkInterfaceTableLabelProvider.java
new file mode 100644
index 00000000..53610c3b
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/NetworkInterfaceTableLabelProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+
+import org.gluster.storage.management.console.views.GlusterServerSummaryView.NETWORK_INTERFACE_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.NetworkInterface;
+
+
+public class NetworkInterfaceTableLabelProvider extends TableLabelProviderAdapter {
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof NetworkInterface)) {
+ return null;
+ }
+
+ NetworkInterface networkInterface = (NetworkInterface) element;
+ String columnText = (columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.INTERFACE.ordinal() ? networkInterface.getName()
+ : columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.MODEL.ordinal() ? networkInterface.getModel()
+ : columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.SPEED.ordinal() ? networkInterface.getSpeed()
+ : columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.IP_ADDRESS.ordinal() ? networkInterface.getIpAddress()
+ : columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.NETMASK.ordinal() ? networkInterface.getNetMask()
+ : columnIndex == NETWORK_INTERFACE_TABLE_COLUMN_INDICES.GATEWAY.ordinal() ? networkInterface.getDefaultGateway()
+ : "Invalid");
+ return ((columnText == null || columnText.trim().equals("")) ? CoreConstants.NA : columnText);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Perspective.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Perspective.java
new file mode 100644
index 00000000..e2a867ed
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/Perspective.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+public class Perspective implements IPerspectiveFactory {
+
+ /**
+ * The ID of the perspective as specified in the extension.
+ */
+ public static final String ID = Perspective.class.getName();
+
+ public void createInitialLayout(IPageLayout layout) {
+ layout.setEditorAreaVisible(false);
+ //layout.addStandaloneView(ClusterView.ID, false, IPageLayout.LEFT, 0.30f, layout.getEditorArea());
+ //layout.addStandaloneView(DetailsView.ID, false, IPageLayout.RIGHT, 0.70f, layout.getEditorArea());
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerDiskTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerDiskTableLabelProvider.java
new file mode 100644
index 00000000..aa4c23c4
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerDiskTableLabelProvider.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.ServerDisksPage.SERVER_DISK_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Partition;
+import org.gluster.storage.management.core.model.Device.DEVICE_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+import static org.gluster.storage.management.console.DeviceTableLabelProvider.DEVICE_COLUMN_INDICES;
+
+
+public class ServerDiskTableLabelProvider extends TableLabelProviderAdapter {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private GlusterDataModelManager glusterDataModelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (!(element instanceof Device)) {
+ return null;
+ }
+
+ Device device = (Device) element;
+ if (columnIndex == SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal()) {
+ DEVICE_STATUS status = device.getStatus();
+
+ if (status == null) {
+ return null;
+ }
+
+ if(element instanceof Disk && ((Disk)element).hasPartitions()) {
+ // disk has partitions. so don't show status image at disk level.
+ return null;
+ }
+
+ switch (status) {
+ case INITIALIZED:
+ if(glusterDataModelManager.isDeviceUsed(device)) {
+ return guiHelper.getImage(IImageKeys.DISK_IN_USE_16x16);
+ } else {
+ return guiHelper.getImage(IImageKeys.DISK_AVAILABLE_16x16);
+ }
+ case IO_ERROR:
+ return guiHelper.getImage(IImageKeys.IO_ERROR_16x16);
+ case UNINITIALIZED:
+ return guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED_16x16);
+ case INITIALIZING:
+ return guiHelper.getImage(IImageKeys.DISK_INITIALIZING_16x16);
+ default:
+ throw new GlusterRuntimeException("Invalid disk status [" + status + "]");
+ }
+ }
+
+ return null;
+ }
+
+ private String getDeviceFreeSpace(Device device) {
+ if (device.hasErrors() || device.isUninitialized()) {
+ return "NA";
+ } else {
+ return NumberUtil.formatNumber((device.getFreeSpace() / 1024));
+ }
+ }
+
+ private String getTotalDeviceSpace(Device device) {
+ if (device.hasErrors() || device.isUninitialized()) {
+ return "NA";
+ } else {
+ return NumberUtil.formatNumber((device.getSpace() / 1024));
+ }
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ Device device = (Device) element;
+ if (columnIndex == DEVICE_COLUMN_INDICES.DISK.ordinal()) {
+ // show value in "disk" column only if it's a disk
+ if (device instanceof Disk) {
+ return device.getName();
+ } else {
+ return "";
+ }
+ }
+
+ if(element instanceof Disk && ((Disk)element).hasPartitions()) {
+ // disk has partitions. so don't show any other details
+ return "";
+ }
+
+ if (columnIndex == DEVICE_COLUMN_INDICES.FREE_SPACE.ordinal()) {
+ return "" + getDeviceFreeSpace(device);
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.SPACE_IN_USE.ordinal()) {
+ return "" + getTotalDeviceSpace(device);
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.PARTITION.ordinal()) {
+ if (device instanceof Partition) {
+ return device.getName();
+ } else {
+ return "";
+ }
+ } else if (columnIndex == DEVICE_COLUMN_INDICES.STATUS.ordinal()) {
+ if(device.isUninitialized()) {
+ return "";
+ }
+ if(glusterDataModelManager.isDeviceUsed(device)) {
+ return "In Use";
+ } else {
+ return device.getStatusStr();
+ }
+ } else {
+ return "";
+ }
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerTableLabelProvider.java
new file mode 100644
index 00000000..1afbddac
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/ServerTableLabelProvider.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.ServersPage.SERVER_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class ServerTableLabelProvider extends TableLabelProviderAdapter {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Server)) {
+ return null;
+ }
+
+ Server server = (Server) element;
+ return (columnIndex == SERVER_TABLE_COLUMN_INDICES.NAME.ordinal() ? server.getName()
+ : columnIndex == SERVER_TABLE_COLUMN_INDICES.IP_ADDRESSES.ordinal() ? server.getIpAddressesAsString()
+ : columnIndex == SERVER_TABLE_COLUMN_INDICES.NUM_OF_DISKS.ordinal() ? ""
+ + server.getNumOfDisks() : columnIndex == SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE
+ .ordinal() ? NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024))
+ // : columnIndex == SERVER_TABLE_COLUMN_INDICES.NUM_OF_CPUS.ordinal() ? "" +
+ // server.getNumOfCPUs()
+ // : columnIndex == SERVER_TABLE_COLUMN_INDICES.CPU_USAGE.ordinal() ? "" + server.getCpuUsage()
+ // : columnIndex == SERVER_TABLE_COLUMN_INDICES.TOTAL_MEMORY.ordinal() ? "" +
+ // server.getTotalMemory()
+ // : columnIndex == SERVER_TABLE_COLUMN_INDICES.MEMORY_IN_USE.ordinal() ? "" +
+ // server.getMemoryInUse()
+ // : columnIndex == SERVER_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE.ordinal() ? "" +
+ // server.getDiskSpaceInUse()
+ : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TableLabelProviderAdapter.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TableLabelProviderAdapter.java
new file mode 100644
index 00000000..622d3dfc
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TableLabelProviderAdapter.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+public class TableLabelProviderAdapter implements ITableLabelProvider {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ // do nothing
+
+ }
+
+ @Override
+ public void dispose() {
+ // do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return true;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ // do nothing
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ return null;
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TasksTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TasksTableLabelProvider.java
new file mode 100644
index 00000000..ad2a8a7d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/TasksTableLabelProvider.java
@@ -0,0 +1,71 @@
+/**
+ * TasksTableLabelProvider.java
+ *
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.TasksPage.TASK_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+
+
+
+public class TasksTableLabelProvider extends TableLabelProviderAdapter {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+
+ if (!(element instanceof TaskInfo)) {
+ return null;
+ }
+
+ TaskInfo taskInfo = (TaskInfo) element;
+ if (columnIndex == TASK_TABLE_COLUMN_INDICES.STATUS.ordinal()) {
+ int statusCode = taskInfo.getStatus().getCode();
+
+ switch (statusCode) {
+ case Status.STATUS_CODE_SUCCESS:
+ return guiHelper.getImage(IImageKeys.COMPLETED_TASK_16x16);
+ case Status.STATUS_CODE_PAUSE:
+ return guiHelper.getImage(IImageKeys.PAUSE_TASK_16x16);
+ case Status.STATUS_CODE_RUNNING:
+ return guiHelper.getImage(IImageKeys.RESUME_TASK_16x16);
+ case Status.STATUS_CODE_FAILURE:
+ return guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16);
+ default:
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof TaskInfo)) {
+ return null;
+ }
+
+ TaskInfo taskInfo = (TaskInfo) element;
+ return (columnIndex == TASK_TABLE_COLUMN_INDICES.TASK.ordinal()) ? taskInfo.getDescription().trim() : taskInfo.getStatus().getMessage().trim();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeLogTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeLogTableLabelProvider.java
new file mode 100644
index 00000000..246bd7ca
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeLogTableLabelProvider.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+
+import org.gluster.storage.management.console.views.pages.VolumeLogsPage.LOG_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.VolumeLogMessage;
+import org.gluster.storage.management.core.utils.DateUtil;
+
+
+public class VolumeLogTableLabelProvider extends TableLabelProviderAdapter {
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof VolumeLogMessage)) {
+ return null;
+ }
+
+ VolumeLogMessage logMessage = (VolumeLogMessage) element;
+ return (columnIndex == LOG_TABLE_COLUMN_INDICES.DATE.ordinal() ? DateUtil.formatDate(logMessage.getTimestamp())
+ : columnIndex == LOG_TABLE_COLUMN_INDICES.TIME.ordinal() ? DateUtil.formatTime(logMessage.getTimestamp())
+ : columnIndex == LOG_TABLE_COLUMN_INDICES.BRICK.ordinal() ? logMessage.getBrick()
+ : columnIndex == LOG_TABLE_COLUMN_INDICES.SEVERITY.ordinal() ? "" + logMessage.getSeverity()
+ : columnIndex == LOG_TABLE_COLUMN_INDICES.MESSAGE.ordinal() ? logMessage.getMessage() : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsContentProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsContentProvider.java
new file mode 100644
index 00000000..0cc0b536
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsContentProvider.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.gluster.storage.management.core.model.VolumeOptions;
+
+
+/**
+ * @author root
+ *
+ */
+public class VolumeOptionsContentProvider implements IStructuredContentProvider {
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof VolumeOptions) {
+ return ((VolumeOptions) inputElement).getOptions().toArray();
+ }
+ return null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsTableLabelProvider.java
new file mode 100644
index 00000000..250066bc
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeOptionsTableLabelProvider.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 org.gluster.storage.management.console;
+
+import java.util.Map.Entry;
+
+import org.gluster.storage.management.console.views.pages.VolumeOptionsPage.OPTIONS_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.VolumeOption;
+
+
+public class VolumeOptionsTableLabelProvider extends TableLabelProviderAdapter {
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Entry)) {
+ return null;
+ }
+
+ VolumeOption option = (VolumeOption)element;
+ return (columnIndex == OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal() ? option.getKey()
+ : columnIndex == OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal() ? option.getValue()
+ : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeTableLabelProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeTableLabelProvider.java
new file mode 100644
index 00000000..e19a40b1
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/VolumeTableLabelProvider.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console;
+
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.VolumesPage.VOLUME_TABLE_COLUMN_INDICES;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+
+
+public class VolumeTableLabelProvider implements ITableLabelProvider {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (!(element instanceof Volume)) {
+ return null;
+ }
+
+ Volume volume = (Volume) element;
+ if(columnIndex == VOLUME_TABLE_COLUMN_INDICES.VOLUME_STATUS.ordinal()) {
+ VOLUME_STATUS status = volume.getStatus();
+ if(status == VOLUME_STATUS.ONLINE) {
+ return guiHelper.getImage(IImageKeys.STATUS_ONLINE_16x16);
+ } else {
+ return guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Volume)) {
+ return null;
+ }
+
+ Volume volume = (Volume) element;
+ return (columnIndex == VOLUME_TABLE_COLUMN_INDICES.NAME.ordinal() ? volume.getName()
+ : columnIndex == VOLUME_TABLE_COLUMN_INDICES.VOLUME_TYPE.ordinal() ? volume.getVolumeTypeStr()
+ : columnIndex == VOLUME_TABLE_COLUMN_INDICES.TRANSPORT_TYPE.ordinal() ? volume.getTransportTypeStr()
+ : columnIndex == VOLUME_TABLE_COLUMN_INDICES.NUM_OF_BRICKS.ordinal() ? "" + volume.getNumOfBricks()
+ : columnIndex == VOLUME_TABLE_COLUMN_INDICES.VOLUME_STATUS.ordinal() ? volume.getStatusStr() : "Invalid");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractActionDelegate.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractActionDelegate.java
new file mode 100644
index 00000000..efff2a3d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractActionDelegate.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.internal.UIPlugin;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.model.Entity;
+
+
+/**
+ * All action delegates in the application should extend from this class. It provides common functionality of grabbing
+ * the Window object on initialization and extracting the selected entity in case of selection change on the navigation
+ * tree.
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractActionDelegate implements IWorkbenchWindowActionDelegate {
+ protected IWorkbenchWindow window;
+ protected static final GlusterLogger logger = GlusterLogger.getInstance();
+
+ // the latest selected entity
+ protected Entity selectedEntity;
+
+ @Override
+ public void run(final IAction action) {
+ try {
+ performAction(action);
+ } catch (final Exception e) {
+ final String actionDesc = action.getDescription();
+ logger.error("Exception while running action [" + actionDesc + "]", e);
+ showErrorDialog(actionDesc, e.getMessage());
+ }
+ }
+
+ abstract protected void performAction(final IAction action);
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ if (selection instanceof StructuredSelection) {
+ Entity selectedEntity = (Entity) ((StructuredSelection) selection).getFirstElement();
+
+ if (this.selectedEntity == selectedEntity) {
+ // entity selection has not changed. do nothing.
+ return;
+ }
+
+ if (selectedEntity != null) {
+ this.selectedEntity = selectedEntity;
+ }
+ }
+ }
+
+ @Override
+ public void init(IWorkbenchWindow window) {
+ this.window = window;
+ }
+
+ protected Shell getShell() {
+ return getWindow().getShell();
+ }
+
+ protected IWorkbenchWindow getWindow() {
+ return window == null ? UIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() : window;
+ }
+
+ protected void showInfoDialog(final String title, final String message) {
+ MessageDialog.openInformation(getShell(), title, message);
+ }
+
+ protected void showWarningDialog(final String title, final String message) {
+ MessageDialog.openWarning(getShell(), title, message);
+ }
+
+ protected void showErrorDialog(final String title, final String message) {
+ MessageDialog.openError(getShell(), title, message);
+ }
+
+ protected boolean showConfirmDialog(final String title, final String message) {
+ return MessageDialog.openQuestion(getShell(), title, message);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractMonitoredActionDelegate.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractMonitoredActionDelegate.java
new file mode 100644
index 00000000..00972f9f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AbstractMonitoredActionDelegate.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.gluster.storage.management.console.ConsoleConstants;
+
+
+/**
+ * Any action that can potentially run for a long time, and supports monitoring and progress dialog should extend from
+ * this class
+ */
+public abstract class AbstractMonitoredActionDelegate extends AbstractActionDelegate {
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.actions.AbstractActionDelegate#performAction(org.eclipse.jface.action.IAction)
+ */
+ @Override
+ protected void performAction(final IAction action) {
+ try {
+ new ProgressMonitorDialog(getShell()).run(false, false, new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ performAction(action, monitor);
+ }
+ });
+ } catch (Exception e) {
+ String errMsg = "Exception while performing action [" + action.getDescription() + "] : [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ showErrorDialog(ConsoleConstants.CONSOLE_TITLE, errMsg);
+ }
+ }
+
+ abstract void performAction(IAction action, IProgressMonitor monitor);
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ActionConstants.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ActionConstants.java
new file mode 100644
index 00000000..bde96570
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ActionConstants.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+public class ActionConstants {
+ public static final String ACTION_SET_CLUSTER = "org.gluster.storage.management.console.actionsets.gluster";
+ public static final String ACTION_SET_VOLUMES = "org.gluster.storage.management.console.actionsets.volumes";
+ public static final String ACTION_SET_VOLUME = "org.gluster.storage.management.console.actionsets.volume";
+ public static final String ACTION_SET_DISKS = "org.gluster.storage.management.console.actionsets.disks";
+ public static final String ACTION_SET_DISK = "org.gluster.storage.management.console.actionsets.disk";
+ public static final String ACTION_SET_GLUSTER_SERVERS = "org.gluster.storage.management.console.actionsets.glusterservers";
+ public static final String ACTION_SET_GLUSTER_SERVER = "org.gluster.storage.management.console.actionsets.glusterserver";
+ public static final String ACTION_SET_DISCOVERED_SERVERS = "org.gluster.storage.management.console.actionsets.serversdiscovered";
+ public static final String ACTION_SET_DISCOVERED_SERVER = "org.gluster.storage.management.console.actionsets.serverdiscovered";
+ public static final String ACTION_SET_TASK = "org.gluster.storage.management.console.actionsets.task";
+ public static final String ACTION_SET_EDIT = "org.gluster.storage.management.console.actionsets.edit";
+
+ public static final String COMMAND_CREATE_VOLUME = "org.gluster.storage.management.console.commands.CreateVolume";
+ public static final String COMMAND_ADD_SERVER = "org.gluster.storage.management.console.commands.AddServer";
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddBrickAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddBrickAction.java
new file mode 100644
index 00000000..e67cf9ab
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddBrickAction.java
@@ -0,0 +1,64 @@
+/**
+ * AddBrickAction.java
+ *
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.dialogs.AddBrickWizard;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class AddBrickAction extends AbstractActionDelegate {
+ private Volume volume;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ public void dispose() {
+ window = null;
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ // TODO: open a dialog box
+ // MessageDialog.openInformation(getShell(), "Action captured", action.getDescription() + "\n" +
+ // volume.getName());
+ AddBrickWizard wizard = new AddBrickWizard(volume); // Also add single page
+
+ WizardDialog dialog = new WizardDialog(getShell(), wizard);
+ dialog.create();
+ dialog.getShell().setSize(1024, 600);
+ dialog.open();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+
+ if (selectedEntity instanceof Volume) {
+ this.volume = (Volume) selectedEntity;
+ // action.setEnabled(volume.getStatus() == VOLUME_STATUS.ONLINE);
+ }
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddServerAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddServerAction.java
new file mode 100644
index 00000000..2a622384
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/AddServerAction.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.dialogs.ServerAdditionDialog;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Server;
+
+
+public class AddServerAction extends AbstractMonitoredActionDelegate {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ protected void performAction(final IAction action, IProgressMonitor monitor) {
+ GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ GlusterServersClient glusterServersClient = new GlusterServersClient();
+
+ Set<Server> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(), Server.class);
+ Set<Server> successServers = new HashSet<Server>();
+ Set<Server> partSuccessServers = new HashSet<Server>();
+ String errMsg = "";
+ String partErrMsg = "";
+
+ if (selectedServers.isEmpty()) {
+ monitor.beginTask("Starting Manual Server Addition", 1);
+ addServerManually();
+ monitor.worked(1);
+ monitor.done();
+ return;
+ }
+
+ monitor.beginTask("Adding Selected Servers...", selectedServers.size());
+ for (Server server : selectedServers) {
+ if(monitor.isCanceled()) {
+ break;
+ }
+
+ monitor.setTaskName("Adding server [" + server.getName() + "]...");
+
+ try {
+ URI newServerURI = glusterServersClient.addServer(server.getName());
+ modelManager.addGlusterServer(glusterServersClient.getGlusterServer(newServerURI));
+ successServers.add(server);
+ } catch (Exception e) {
+ if (!errMsg.isEmpty()) {
+ errMsg += CoreConstants.NEWLINE;
+ }
+ errMsg += "Server " + server.getName() + ". Error: [" + e.getMessage() + "]";
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+
+ showStatusMessage(action.getDescription(), selectedServers, successServers, partSuccessServers, errMsg,
+ partErrMsg);
+ }
+
+ private void addServerManually() {
+ try {
+ // To open a dialog for server addition
+ ServerAdditionDialog dialog = new ServerAdditionDialog(getShell());
+ dialog.open();
+ } catch (Exception e) {
+ logger.error("Error in Manual server addition", e);
+ showErrorDialog("Add server", "Add server failed! [" + e.getMessage() + "]");
+ }
+ }
+
+ private void showStatusMessage(String dialogTitle, Set<Server> selectedServers, Set<Server> successServers,
+ Set<Server> partSuccessServers, String errMsg, String partErrMsg) {
+ if (successServers.size() == selectedServers.size()) {
+ if (selectedServers.size() == 1) {
+ showInfoDialog(dialogTitle, "Server [" + selectedServers.iterator().next() + "] added successfully!");
+ } else {
+ showInfoDialog(dialogTitle, "Following servers added successfully!" + CoreConstants.NEWLINE
+ + selectedServers);
+ }
+ return;
+ }
+
+ String finalMsg = "";
+ if (successServers.size() == 0 && partSuccessServers.size() == 0) {
+ finalMsg = "Server Addition Failed! Error(s):" + CoreConstants.NEWLINE + errMsg;
+ } else {
+ finalMsg = (successServers.isEmpty() ? "" : "Following servers added successfully : "
+ + CoreConstants.NEWLINE + successServers + CoreConstants.NEWLINE)
+ + (partSuccessServers.isEmpty() ? "" : "Following servers were added to cluster, but with some errors: "
+ + CoreConstants.NEWLINE + partErrMsg + CoreConstants.NEWLINE)
+ + (errMsg.isEmpty() ? "" : CoreConstants.NEWLINE
+ + "Following errors occurred on other selected servers: " + CoreConstants.NEWLINE + errMsg);
+ }
+ showErrorDialog(dialogTitle, finalMsg);
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Disposing [" + this.getClass().getSimpleName() + "]");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ChangePasswordAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ChangePasswordAction.java
new file mode 100644
index 00000000..07d59332
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ChangePasswordAction.java
@@ -0,0 +1,23 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.console.dialogs.ChangePasswordDialog;
+
+
+public class ChangePasswordAction extends AbstractActionDelegate {
+
+ @Override
+ protected void performAction(IAction action) {
+ try {
+ // To open a dialog for change password
+ ChangePasswordDialog dialog = new ChangePasswordDialog(getShell());
+ dialog.open();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ClearTaskAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ClearTaskAction.java
new file mode 100644
index 00000000..fcdb67ee
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ClearTaskAction.java
@@ -0,0 +1,46 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+
+
+public class ClearTaskAction extends AbstractActionDelegate {
+ private TaskInfo taskInfo;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+
+ try {
+ new TasksClient().deleteTask(taskInfo.getName()); // taskId
+ modelManager.removeTask(taskInfo);
+ action.setEnabled(false); // TODO disable other task buttons
+ } catch (Exception e) {
+ showErrorDialog(actionDesc,
+ "Task [" + taskInfo.getName() + "] could not be cleared! Error: [" + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ if (selectedEntity instanceof TaskInfo) {
+ taskInfo = (TaskInfo) selectedEntity;
+ action.setEnabled(taskInfo.getStatus().getCode() == Status.STATUS_CODE_SUCCESS
+ || taskInfo.getStatus().getCode() == Status.STATUS_CODE_FAILURE);
+ } else {
+ action.setEnabled(false);
+ }
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CommitTaskAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CommitTaskAction.java
new file mode 100644
index 00000000..3fb59f91
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CommitTaskAction.java
@@ -0,0 +1,72 @@
+package org.gluster.storage.management.console.actions;
+
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class CommitTaskAction extends AbstractActionDelegate {
+ private TaskInfo taskInfo;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+ try {
+ new TasksClient().commitTask(taskInfo.getName());
+ taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_SUCCESS, "Committed")));
+ modelManager.removeTask(taskInfo);
+ showInfoDialog(actionDesc, "Commit successful");
+ } catch (Exception e) {
+ showErrorDialog(actionDesc,
+ "Task [" + taskInfo.getName() + "] could not be Committed! Error: [" + e.getMessage() + "]");
+ return; // Prevent to update model
+ }
+
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String volumeName = taskInfo.getReference().split("#")[0]; //Extract volume name from reference
+ Volume oldVolume = modelManager.getModel().getCluster().getVolume(volumeName);
+ Volume newVolume = (new VolumesClient()).getVolume(volumeName);
+
+ modelManager.volumeChanged(oldVolume, newVolume);
+ } catch (Exception e) {
+ String errMsg = "Volume brick update failed! [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ showInfoDialog(actionDesc, errMsg);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ if (selectedEntity instanceof TaskInfo) {
+ taskInfo = (TaskInfo) selectedEntity;
+ action.setEnabled(taskInfo.getCommitSupported()
+ && taskInfo.getStatus().getCode() == Status.STATUS_CODE_COMMIT_PENDING);
+ }
+ }
+
+ public void updateVolume(String volumeName) {
+
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CreateVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CreateVolumeAction.java
new file mode 100644
index 00000000..55d10eda
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/CreateVolumeAction.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.gluster.storage.management.console.dialogs.CreateVolumeWizard;
+
+
+public class CreateVolumeAction extends AbstractActionDelegate {
+ @Override
+ protected void performAction(IAction action) {
+ CreateVolumeWizard wizard = new CreateVolumeWizard();
+
+ WizardDialog dialog = new WizardDialog(getShell(), wizard) {
+ @Override
+ protected Button createButton(Composite parent, int id, String label, boolean defaultButton) {
+ Button button = super.createButton(parent, id, label, defaultButton);
+ if (id == IDialogConstants.FINISH_ID) {
+ button.setText("&Create");
+ }
+ return button;
+ }
+ };
+ dialog.create();
+ dialog.getShell().setSize(510, 620);
+ dialog.open();
+ }
+
+ @Override
+ public void dispose() {
+ window = null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DeleteVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DeleteVolumeAction.java
new file mode 100644
index 00000000..fb9e4cc2
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DeleteVolumeAction.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+
+
+public class DeleteVolumeAction extends AbstractMonitoredActionDelegate {
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private List<Volume> selectedVolumes = new ArrayList<Volume>();
+ private List<String> selectedVolumeNames = new ArrayList<String>();
+ private List<String> onlineVolumeNames = new ArrayList<String>();
+ private List<String> deletedVolumeNames = new ArrayList<String>();
+ private List<Volume> failedVolumes = new ArrayList<Volume>();
+
+ @Override
+ protected void performAction(final IAction action, IProgressMonitor monitor) {
+ final String actionDesc = action.getDescription();
+
+ collectVolumeNames();
+ String warningMessage;
+ List<String> cifsVolumes = GlusterDataModelManager.getInstance().getCifsEnabledVolumeNames(selectedVolumes);
+ List<String> offlineServers = GlusterDataModelManager.getInstance().getOfflineServers();
+ // One or more servers are offline, Show warning if cifs is enabled
+ if (cifsVolumes != null && cifsVolumes.size() > 0 && offlineServers != null && offlineServers.size() > 0) {
+ Integer userAction = new MessageDialog(getShell(), "CIFS configuration", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16),
+ "Performing CIFS updates when one or more servers are offline can trigger "
+ + "inconsistent behavior for CIFS accesses in the cluster." + CoreConstants.NEWLINE
+ + "Are you sure you want to continue?", MessageDialog.QUESTION,
+ new String[] { "No", "Yes" }, -1).open();
+ if (userAction != 1) {
+ return; // Do not delete volume services
+ }
+ }
+
+ if (onlineVolumeNames.size() > 0) { // Getting confirmation for stop and delete
+ warningMessage = "Following volume(s) " + onlineVolumeNames + " are online, " + CoreConstants.NEWLINE
+ + "Are you sure to continue?" + CoreConstants.NEWLINE + selectedVolumeNames;
+ } else {
+ warningMessage = "Are you sure to delete the volumes " + selectedVolumeNames + " ?";
+ }
+
+ final Integer deleteOption = new MessageDialog(getShell(), "Delete Volume", GUIHelper.getInstance()
+ .getImage(IImageKeys.VOLUME_16x16), warningMessage, MessageDialog.QUESTION, new String[] { "Cancel",
+ "Delete volume and data", "Delete volume, keep data" }, -1).open();
+ if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1)
+ return;
+ }
+
+ String errorMessage = deleteVolumes(selectedVolumes, deleteOption, monitor);
+
+ // Display the success or failure info
+ if (deletedVolumeNames.size() == 0) { // No volume(s) deleted successfully
+ showErrorDialog(actionDesc, "Volume(s) could not be deleted! " + CoreConstants.NEWLINE + errorMessage);
+ } else {
+ String info = "Volume(s) " + deletedVolumeNames + " deleted successfully!";
+ if (!failedVolumes.isEmpty()) {
+ info += CoreConstants.NEWLINE + CoreConstants.NEWLINE + "Volumes " + failedVolumes
+ + " could not be deleted!" + CoreConstants.NEWLINE + errorMessage;
+ }
+
+ if (selectedVolumes.size() == deletedVolumeNames.size()) {
+ showInfoDialog(actionDesc, info);
+ } else {
+ showWarningDialog(actionDesc, info);
+ }
+ }
+ }
+
+ private String deleteVolumes(List<Volume> volumes, final Integer deleteOption, IProgressMonitor monitor) {
+ deletedVolumeNames.clear();
+ failedVolumes.clear();
+ VolumesClient vc = new VolumesClient();
+ boolean confirmDeleteDir = (deleteOption == 1) ? true : false;
+
+ String errorMessage = "";
+
+ // To calculate the total work we need to sum volumes size + online volumes (because we treat stop and delete as
+ // separate steps)
+ List<Volume> onlineVolumes = getOnlineVolumes(volumes);
+ monitor.beginTask("Deleting Selected Volumes...", volumes.size() + onlineVolumes.size());
+
+ // Deletion of a volume results in changes to the model, and ultimately updates the "selectedVolumes" list,
+ // over which we are iterating, thus resulting in ConcurrentModificationException. To avoid this, we iterate
+ // over an array obtained from the list.
+ for (Volume volume : volumes.toArray(new Volume[0])) {
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) { // stop if online volume
+ monitor.setTaskName("Stopping volume [" + volume.getName() + "]");
+ try {
+ vc.stopVolume(volume.getName(), false);
+ } catch (Exception e1) {
+ // try again with force = true
+ try {
+ vc.stopVolume(volume.getName(), true);
+ } catch(Exception e2) {
+ // force stop also failed.
+ // Mark as deletion failed, append error message.
+ errorMessage += CoreConstants.NEWLINE + "Stop [" + volume.getName() + "] : [" + e2.getMessage()
+ + "]";
+ failedVolumes.add(volume);
+ // since we are not going to perform delete on this volume,
+ // mark the deletion task as worked
+ monitor.worked(1);
+
+ // continue to next volume without trying to delete this one
+ continue;
+ }
+ } finally {
+ // worked for "stop" operation
+ monitor.worked(1);
+ }
+ }
+
+ monitor.setTaskName("Deleting volume [" + volume.getName() + "]");
+ try {
+ vc.deleteVolume(volume.getName(), confirmDeleteDir);
+ modelManager.deleteVolume(volume);
+ deletedVolumeNames.add(volume.getName());
+ } catch (Exception e) {
+ // Volume delete succeeded and post delete operation (directory cleanup, CIFS etc) may fail
+ if (vc.volumeExists(volume.getName())) {
+ errorMessage += CoreConstants.NEWLINE + "Delete [" + volume.getName() + "] : [" + e.getMessage() + "]";
+ failedVolumes.add(volume);
+ } else {
+ errorMessage += CoreConstants.NEWLINE + "Volume [" + volume.getName()
+ + "] deleted, but following error occured: [" + e.getMessage() + "]";
+ modelManager.deleteVolume(volume);
+ deletedVolumeNames.add(volume.getName());
+ }
+ } finally {
+ monitor.worked(1);
+ }
+ }
+ monitor.done();
+ return errorMessage;
+ }
+
+ private List<Volume> getOnlineVolumes(List<Volume> volumes) {
+ List<Volume> onlineVolumes = new ArrayList<Volume>();
+ for (Volume volume : volumes) {
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ onlineVolumes.add(volume);
+ }
+ }
+ return onlineVolumes;
+ }
+
+ private void collectVolumeNames() {
+ selectedVolumeNames.clear();
+ onlineVolumeNames.clear();
+ for (Volume volume : selectedVolumes) {
+ selectedVolumeNames.add(volume.getName());
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ onlineVolumeNames.add(volume.getName());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Disposing [" + this.getClass().getSimpleName() + "]");
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ Set<Volume> selectedVolumeSet = GUIHelper.getInstance().getSelectedEntities(getWindow(), Volume.class);
+ selectedVolumes.clear();
+ if (selectedVolumeSet == null || selectedVolumeSet.isEmpty()) {
+ super.selectionChanged(action, selection);
+ if (selectedEntity instanceof Volume) {
+ selectedVolumes.add((Volume) selectedEntity);
+ }
+ } else {
+ selectedVolumes.addAll(selectedVolumeSet); //TODO reverse the collection to maintain the selected order
+ }
+
+ action.setEnabled( (selectedVolumes.size() > 0) );
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DownloadVolumeLogsAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DownloadVolumeLogsAction.java
new file mode 100644
index 00000000..b67e0b2e
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/DownloadVolumeLogsAction.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Volume;
+
+
+/**
+ *
+ */
+public class DownloadVolumeLogsAction extends AbstractActionDelegate {
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ final VolumesClient client = new VolumesClient();
+ Volume volume = guiHelper.getSelectedEntity(getWindow(), Volume.class);
+
+ FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
+ dialog.setFilterNames(new String[] { "GZipped Tar (*.tar.gz)" });
+ dialog.setFilterExtensions(new String[] { "*.tar.gz" });
+ String filePath = dialog.open();
+
+ if (filePath == null) {
+ return;
+ }
+
+ String title = "Download Volume Logs [" + volume.getName() + "]";
+ try {
+ client.downloadLogs(volume.getName(), filePath);
+ showInfoDialog(title, "Volume logs downloaded successfully to [" + filePath + "]");
+ } catch (Exception e) {
+ showErrorDialog(title, e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/EditVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/EditVolumeAction.java
new file mode 100644
index 00000000..efb7b780
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/EditVolumeAction.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+
+public class EditVolumeAction extends AbstractActionDelegate {
+ @Override
+ protected void performAction(IAction action) {
+ System.out.println("Running [" + this.getClass().getSimpleName() + "]");
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Disposing [" + this.getClass().getSimpleName() + "]");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ExportSshKeysAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ExportSshKeysAction.java
new file mode 100644
index 00000000..a4b57800
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ExportSshKeysAction.java
@@ -0,0 +1,61 @@
+/**
+ * ExportSshKeysAction.java
+ *
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.gluster.storage.management.client.KeysClient;
+
+
+/**
+ * @author root
+ *
+ */
+public class ExportSshKeysAction extends AbstractActionDelegate {
+
+ @Override
+ protected void performAction(IAction action) {
+ final KeysClient client = new KeysClient();
+ FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
+ dialog.setFilterNames(new String[] { "Tar (*.tar)" });
+ dialog.setFilterExtensions(new String[] { "*.tar" });
+ String filePath = dialog.open();
+
+ if (filePath == null) {
+ return;
+ }
+
+ String title = "Export SSH Keys";
+ try {
+ client.exportSshKeys(filePath);
+ showInfoDialog(title, "SSH keys exported successfully to [" + filePath + "]");
+ } catch (Exception e) {
+ showErrorDialog(title, e.getMessage());
+ }
+ }
+
+
+ @Override
+ public void dispose() {
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ForceStartVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ForceStartVolumeAction.java
new file mode 100644
index 00000000..3c57256a
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ForceStartVolumeAction.java
@@ -0,0 +1,71 @@
+package org.gluster.storage.management.console.actions;
+
+import java.util.Set;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.VolumeBricksView;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.utils.StringUtil;
+
+
+public class ForceStartVolumeAction extends AbstractActionDelegate {
+
+ private Volume volume;
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private Set<Brick> bricks;
+
+ @Override
+ public void dispose() {
+
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ // volume brick service will be started, do you want to continue?
+ final String actionDesc = action.getDescription();
+ boolean confirmed = showConfirmDialog(
+ actionDesc,
+ "The offline Bricks [" + StringUtil.collectionToString(bricks, ", ") + "] of Volume ["
+ + volume.getName() + "] will be started. Are you sure you want to continue?");
+ if (!confirmed) {
+ return;
+ }
+ try {
+ new VolumesClient().startVolume(volume.getName(), true);
+ showInfoDialog(actionDesc, "Offline Bricks of Volume [" + volume.getName() + "] started successfully!");
+ } catch (Exception e) {
+ showErrorDialog(actionDesc, e.getMessage());
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ volume = guiHelper.getSelectedEntity(window, Volume.class);
+ if (volume != null) {
+ // a volume is selected on navigation tree. Let's check if the currently open view is volume bricks view
+ IWorkbenchPart view = guiHelper.getActiveView();
+ if (view instanceof VolumeBricksView) {
+ // volume bricks view is open. check if any offline brick is selected
+ bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class);
+ for (Brick brick : bricks) {
+ if (brick.getStatus() == BRICK_STATUS.OFFLINE) {
+ action.setEnabled(true);
+ } else {
+ // if any one of the selected brick is online, the disable the button
+ action.setEnabled(false);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ImportSshKeysAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ImportSshKeysAction.java
new file mode 100644
index 00000000..083cf193
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ImportSshKeysAction.java
@@ -0,0 +1,44 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.gluster.storage.management.client.KeysClient;
+
+
+public class ImportSshKeysAction extends AbstractActionDelegate {
+
+ @Override
+ protected void performAction(IAction action) {
+ final KeysClient client = new KeysClient();
+
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
+ dialog.setText("Open");
+ dialog.setFilterNames(new String[] { "ssh-keys (*.tar)" });
+ dialog.setFilterExtensions(new String[] { "*.tar" });
+
+ String selectedFile = dialog.open();
+ if (selectedFile == null) {
+ return;
+ }
+
+ String title = "Import SSH Keys";
+ try {
+ client.importSshKeys(selectedFile);
+ showInfoDialog(title, "SSH keys imported successfully!");
+ } catch (Exception e) {
+ showErrorDialog(title, e.getMessage());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateBrickAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateBrickAction.java
new file mode 100644
index 00000000..01cc837c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateBrickAction.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 org.gluster.storage.management.console.actions;
+
+import java.util.Set;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.gluster.storage.management.console.dialogs.MigrateBrickWizard;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class MigrateBrickAction extends AbstractActionDelegate {
+ private Volume volume;
+ private Brick brick;
+
+ @Override
+ protected void performAction(IAction action) {
+ MigrateBrickWizard wizard = new MigrateBrickWizard(volume, brick);
+
+ WizardDialog dialog = new WizardDialog(window.getShell(), wizard);
+ dialog.create();
+ dialog.getShell().setSize(1024, 600);
+ dialog.open();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ Set<Brick> bricks;
+ if (selectedEntity instanceof Volume) {
+ volume = (Volume) selectedEntity;
+ }
+
+ action.setEnabled(false);
+ if (selectedEntity instanceof Brick) {
+ bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class);
+ if ( bricks.iterator().hasNext()) {
+ brick = bricks.iterator().next();
+ } else {
+ brick = null;
+ }
+ action.setEnabled(brick != null);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateVolumeAction.java
new file mode 100644
index 00000000..ed4b47f6
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/MigrateVolumeAction.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+
+public class MigrateVolumeAction extends AbstractActionDelegate {
+ @Override
+ protected void performAction(IAction action) {
+ System.out.println("Running [" + this.getClass().getSimpleName() + "]");
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Disposing [" + this.getClass().getSimpleName() + "]");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PauseTaskAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PauseTaskAction.java
new file mode 100644
index 00000000..675095ee
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PauseTaskAction.java
@@ -0,0 +1,67 @@
+/**
+ * PauseTaskAction.java
+ *
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+
+
+
+public class PauseTaskAction extends AbstractActionDelegate {
+ private TaskInfo taskInfo;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+
+ try {
+ new TasksClient().pauseTask(taskInfo.getName());
+ taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_PAUSE, "Paused")));
+ modelManager.updateTask(taskInfo);
+ } catch (Exception e) {
+ showErrorDialog(actionDesc,
+ "Task [" + taskInfo.getDescription() + "] could not be Paused! Error: [" + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ if (selectedEntity instanceof TaskInfo) {
+ taskInfo = (TaskInfo) selectedEntity;
+ action.setEnabled(taskInfo.getPauseSupported() && taskInfo.getStatus().getCode() == Status.STATUS_CODE_RUNNING);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PreferencesAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PreferencesAction.java
new file mode 100644
index 00000000..11db53e0
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/PreferencesAction.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.actions.ActionFactory;
+
+public class PreferencesAction extends AbstractActionDelegate {
+
+ @Override
+ public void dispose() {
+
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ ActionFactory.PREFERENCES.create(window).run();
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RebalanceVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RebalanceVolumeAction.java
new file mode 100644
index 00000000..beae73c6
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RebalanceVolumeAction.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.net.URI;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class RebalanceVolumeAction extends AbstractActionDelegate {
+ private Volume volume;
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+ try {
+ TaskInfo existingTaskInfo = GlusterDataModelManager.getInstance().getTaskByReference(volume.getName());
+ if (existingTaskInfo != null && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS
+ && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_FAILURE) {
+ showInfoDialog(actionDesc, "Volume [" + volume.getName()
+ + "] rebalance is already in progress! Try later.");
+ return;
+ }
+
+ URI uri = new VolumesClient().rebalanceStart(volume.getName(), false, false, false);
+ // Add the task to model
+ TasksClient taskClient = new TasksClient();
+ TaskInfo taskInfo = taskClient.getTaskInfo(uri);
+ if (taskInfo != null) {
+ GlusterDataModelManager.getInstance().addTask(taskInfo);
+ }
+ showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] rebalance started successfully!");
+ guiHelper.showTaskView();
+ } catch (Exception e) {
+ showErrorDialog(actionDesc, "Volume rebalance could not be started on [" + volume.getName() + "]! Error: ["
+ + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+
+ Volume selectedVolume = guiHelper.getSelectedEntity(getWindow(), Volume.class);
+ if (selectedVolume != null) {
+ volume = selectedVolume;
+ action.setEnabled(true);
+ } else {
+ action.setEnabled(false);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ System.out.println("Disposing [" + this.getClass().getSimpleName() + "]");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RefreshDataAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RefreshDataAction.java
new file mode 100644
index 00000000..5e791768
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RefreshDataAction.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.console.jobs.DataSyncJob;
+
+
+/**
+ *
+ */
+public class RefreshDataAction extends AbstractActionDelegate {
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
+ */
+ @Override
+ public void dispose() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.actions.AbstractActionDelegate#performAction(org.eclipse.jface.action.IAction)
+ */
+ @Override
+ protected void performAction(IAction action) {
+ new DataSyncJob("Retrieving Management Info").schedule();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveBrickAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveBrickAction.java
new file mode 100644
index 00000000..658394ed
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveBrickAction.java
@@ -0,0 +1,91 @@
+package org.gluster.storage.management.console.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPart;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.VolumeBricksView;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.utils.StringUtil;
+
+
+public class RemoveBrickAction extends AbstractActionDelegate {
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private Set<Brick> bricks;
+ private Volume volume;
+ boolean confirmDelete = false;
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+ List<String> brickList = getBrickList(bricks);
+ Integer deleteOption = new MessageDialog(getShell(), "Remove Bricks(s)", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16), "Are you sure you want to remove following bricks from volume [" + volume.getName()
+ + "] ? " + CoreConstants.NEWLINE + StringUtil.collectionToString(brickList, ", "), MessageDialog.QUESTION, new String[] {
+ "Cancel", "Remove bricks, delete data", "Remove bricks, keep data" }, -1).open();
+ if (deleteOption <= 0) { // By Cancel button(0) or Escape key(-1)
+ return;
+ }
+
+ if (deleteOption == 1) {
+ confirmDelete = true;
+ }
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+ public void run() {
+ VolumesClient client = new VolumesClient();
+ try {
+ client.removeBricks(volume.getName(), bricks, confirmDelete);
+ // Update model with removed bricks in the volume
+ modelManager.removeBricks(volume, bricks);
+
+ showInfoDialog(actionDesc, "Volume [" + volume.getName() + "] bricks(s) removed successfully!");
+ } catch (Exception e) {
+ showErrorDialog(actionDesc, "Volume [" + volume.getName()
+ + "] bricks(s) could not be removed! Error: [" + e.getMessage() + "]");
+ }
+ }
+ });
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+
+ action.setEnabled(false);
+ volume = guiHelper.getSelectedEntity(window, Volume.class);
+ if (volume != null) {
+ // a volume is selected on navigation tree. Let's check if the currently open view is volume bricks view
+ IWorkbenchPart view = guiHelper.getActiveView();
+ if (view instanceof VolumeBricksView) {
+ // volume bricks view is open. check if any brick is selected
+ bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class);
+ action.setEnabled(bricks.size() > 0);
+ }
+ }
+ }
+
+ private List<String> getBrickList(Set<Brick> bricks) {
+ List<String> brickList = new ArrayList<String>();
+ for (Brick brick : bricks) {
+ brickList.add(brick.getServerName() + ":" + brick.getBrickDirectory());
+ }
+ return brickList;
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveServerAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveServerAction.java
new file mode 100644
index 00000000..94f69be8
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/RemoveServerAction.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class RemoveServerAction extends AbstractMonitoredActionDelegate {
+ private static final GlusterLogger logger = GlusterLogger.getInstance();
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ @Override
+ protected void performAction(final IAction action, IProgressMonitor monitor) {
+ final String actionDesc = action.getDescription();
+
+ Set<GlusterServer> selectedServers = guiHelper.getSelectedEntities(getWindow(), GlusterServer.class);
+
+ if (!validate(action, selectedServers)) {
+ return;
+ }
+
+ boolean confirmed = showConfirmDialog(actionDesc, "Are you sure you want to remove the server(s) "
+ + selectedServers + " ?");
+ if (!confirmed) {
+ return;
+ }
+
+ Set<GlusterServer> successServers = new HashSet<GlusterServer>();
+ String errMsg = "";
+ monitor.beginTask("Removing Selected Servers...", selectedServers.size());
+ for (GlusterServer server : selectedServers) {
+ monitor.setTaskName("Removing server [" + server.getName() + "]...");
+
+ GlusterServersClient client = new GlusterServersClient();
+ try {
+ client.removeServer(server.getName());
+ GlusterServer glusterServer = server;
+ modelManager.removeGlusterServer(glusterServer);
+ successServers.add(server);
+ } catch (Exception e) {
+ if (!serverExists(server.getName())) {
+ modelManager.removeGlusterServer(server);
+ }
+ errMsg += "[" + server.getName() + "] : " + e.getMessage() + CoreConstants.NEWLINE;
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+ showStatusMessage(action.getDescription(), selectedServers, successServers, errMsg);
+ }
+
+ private Boolean serverExists(String serverName) {
+ try {
+ GlusterServersClient client = new GlusterServersClient();
+ GlusterServer server = client.getGlusterServer(serverName);
+ return (server != null && server.getName().length() > 0);
+ } catch (Exception e) {
+ logger.error("Error while getting server info", e);
+ return false;
+ }
+ }
+
+ private void showStatusMessage(String dialogTitle, Set<GlusterServer> selectedServers, Set<GlusterServer> successServers,
+ String errMsg) {
+ if (successServers.size() == selectedServers.size()) {
+ if(selectedServers.size() == 1) {
+ showInfoDialog(dialogTitle, "Server [" + selectedServers.iterator().next() + "] removed successfully!");
+ } else {
+ showInfoDialog(dialogTitle, "Following servers removed successfully: " + CoreConstants.NEWLINE
+ + selectedServers + CoreConstants.NEWLINE + errMsg);
+ }
+ return;
+ }
+
+ if (successServers.size() == 0) {
+ errMsg = "Server Removal Failed! Error(s):" + CoreConstants.NEWLINE + errMsg;
+ } else {
+ errMsg = "Following servers removed successfully : " + CoreConstants.NEWLINE + successServers
+ + CoreConstants.NEWLINE + "Following errors occurred on other selected servers: "
+ + CoreConstants.NEWLINE + errMsg;
+ }
+ showErrorDialog(dialogTitle, errMsg);
+ }
+
+ private boolean validate(IAction action, Set<GlusterServer> selectedServers) {
+ Map<GlusterServer, List<String>> usedServers = new HashMap<GlusterServer, List<String>>();
+ for (GlusterServer server : selectedServers) {
+ List<String> configuredVolumes = modelManager.getVolumesOfServer(server.getName());
+
+ if (configuredVolumes.size() > 0) {
+ usedServers.put(server, configuredVolumes);
+ }
+ }
+
+ if (usedServers.size() > 0) {
+ if (usedServers.size() == 1) {
+ showErrorDialog(action.getDescription(), "Server [" + usedServers.keySet().iterator().next()
+ + "] cannot be removed as it is being used by volume(s): " + CoreConstants.NEWLINE
+ + usedServers.values().iterator().next() );
+ } else {
+ String serverList = "";
+ for (Entry<GlusterServer, List<String>> entry : usedServers.entrySet()) {
+ serverList += entry.getKey() + " -> " + entry.getValue() + CoreConstants.NEWLINE;
+ }
+ showErrorDialog(action.getDescription(),
+ "Following servers cannot be removed as they are being used by volume(s): "
+ + CoreConstants.NEWLINE + serverList );
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public void dispose() {
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ Set<GlusterServer> selectedServers = GUIHelper.getInstance().getSelectedEntities(getWindow(),
+ GlusterServer.class);
+ if(selectedServers == null || selectedServers.isEmpty()) {
+ action.setEnabled(false);
+ } else {
+ action.setEnabled(true);
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResetVolumeOptionsAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResetVolumeOptionsAction.java
new file mode 100644
index 00000000..ef21aac7
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResetVolumeOptionsAction.java
@@ -0,0 +1,62 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Display;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class ResetVolumeOptionsAction extends AbstractActionDelegate {
+ private Volume volume;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ protected void performAction(final IAction action) {
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ final String actionDesc = action.getDescription();
+
+ boolean confirmed = showConfirmDialog(actionDesc,
+ "Are you sure you want to reset all options of the volume [" + volume.getName() + "] ?");
+ if (!confirmed) {
+ return;
+ }
+
+ try {
+ new VolumesClient().resetVolumeOptions(volume.getName());
+ showInfoDialog(actionDesc, "Volume options for [" + volume.getName() + "] reset successfully!");
+ modelManager.resetVolumeOptions(volume);
+ } catch (Exception e) {
+ showErrorDialog(actionDesc, "Volume options for [" + volume.getName()
+ + "] could not be reset! Error: [" + e.getMessage() + "]");
+ }
+ }
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.gluster.storage.management.console.actions.AbstractActionDelegate#selectionChanged(org.eclipse.jface.action.IAction
+ * , org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ volume = GUIHelper.getInstance().getSelectedEntity(getWindow(), Volume.class);
+ if (volume != null) {
+ action.setEnabled(volume.getOptions().size() > 0);
+ } else {
+ action.setEnabled(false);
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResumeTaskAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResumeTaskAction.java
new file mode 100644
index 00000000..4ecb283d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ResumeTaskAction.java
@@ -0,0 +1,45 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+
+
+public class ResumeTaskAction extends AbstractActionDelegate {
+ private TaskInfo taskInfo;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+
+ try {
+ new TasksClient().resumeTask(taskInfo.getName());
+ taskInfo.setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, "Resumed")));
+ modelManager.updateTask(taskInfo);
+ } catch (Exception e) {
+ showErrorDialog(actionDesc,
+ "Task [" + taskInfo.getDescription() + "] could not be Resumed! Error: [" + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ if (selectedEntity instanceof TaskInfo) {
+ taskInfo = (TaskInfo) selectedEntity;
+ action.setEnabled(taskInfo.getStatus().getCode() == Status.STATUS_CODE_PAUSE);
+ }
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ServerAdditionAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ServerAdditionAction.java
new file mode 100644
index 00000000..c0ed3beb
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/ServerAdditionAction.java
@@ -0,0 +1,28 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.console.dialogs.ServerAdditionDialog;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+
+
+public class ServerAdditionAction extends AbstractActionDelegate {
+ private static final GlusterLogger logger = GlusterLogger.getInstance();
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ try {
+ // To open a dialog for server addition
+ ServerAdditionDialog dialog = new ServerAdditionDialog(getShell());
+ dialog.open();
+ } catch (Exception e) {
+ logger.error("Error in Manual server addition", e);
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StartVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StartVolumeAction.java
new file mode 100644
index 00000000..4a8db975
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StartVolumeAction.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.osgi.internal.signedcontent.Base64;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.AlertsManager;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Alert.ALERT_TYPES;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+
+
+public class StartVolumeAction extends AbstractMonitoredActionDelegate {
+ //private Volume volume;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private List<Volume> selectedVolumes = new ArrayList<Volume>();
+ private List<String> selectedVolumeNames = new ArrayList<String>();
+ private List<String> offlineVolumeNames = new ArrayList<String>();
+
+ @Override
+ protected void performAction(IAction action, IProgressMonitor monitor) {
+ final String actionDesc = action.getDescription();
+
+ collectVolumeNames();
+
+ if (offlineVolumeNames.size() == 0) {
+ showWarningDialog(actionDesc, "Volumes " + selectedVolumeNames + " already started!");
+ return; // Volume already started. Don't do anything.
+ }
+
+ VolumesClient vc = new VolumesClient();
+ Volume newVolume = new Volume();
+ List<String> startedVolumes = new ArrayList<String>();
+ List<String> failedVolumes = new ArrayList<String>();
+ String errorMessage = "";
+ List<String> cifsVolumes = GlusterDataModelManager.getInstance().getCifsEnabledVolumeNames(selectedVolumes);
+ List<String> offlineServers = GlusterDataModelManager.getInstance().getOfflineServers();
+ // One or more servers are offline, Show warning if cifs is enabled
+ if (cifsVolumes != null && cifsVolumes.size() > 0 && offlineServers != null && offlineServers.size() > 0) {
+ Integer userAction = new MessageDialog(getShell(), "CIFS configuration", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16),
+ "Performing CIFS updates when one or more servers are offline can trigger "
+ + "inconsistent behavior for CIFS accesses in the cluster." + CoreConstants.NEWLINE
+ + "Are you sure you want to continue?", MessageDialog.QUESTION,
+ new String[] { "No", "Yes" }, -1).open();
+ if (userAction != 1) {
+ return; // Do not start volume services
+ }
+ }
+
+ monitor.beginTask("Starting Selected Volumes...", selectedVolumes.size());
+ // Starting of a volume results in changes to the model, and ultimately updates the "selectedVolumes" list,
+ // over which we are iterating, thus resulting in ConcurrentModificationException. To avoid this, we iterate
+ // over an array obtained from the list.
+ for (Volume volume : selectedVolumes.toArray(new Volume[0])) {
+ if(monitor.isCanceled()) {
+ break;
+ }
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ monitor.worked(1);
+ continue; // skip if already started
+ }
+ try {
+ monitor.setTaskName("Starting volume [" + volume.getName() + "]");
+ vc.startVolume(volume.getName(), false);
+ modelManager.updateVolumeStatus(volume, VOLUME_STATUS.ONLINE);
+ startedVolumes.add(volume.getName());
+ } catch (Exception e) {
+ failedVolumes.add(volume.getName());
+ // If any post volume start activity failed, update the volume status
+ if (vc.getVolume(volume.getName()).getStatus() == VOLUME_STATUS.ONLINE) {
+ modelManager.updateVolumeStatus(volume, VOLUME_STATUS.ONLINE);
+ }
+ errorMessage += e.getMessage() + CoreConstants.NEWLINE;
+ }
+
+ // Update the model by fetching latest volume info (NOT JUST STATUS)
+ try {
+ modelManager.refreshVolumeData(volume);
+ } catch (Exception e) {
+ errorMessage += "Updating volume info failed on UI. [" + e.getMessage() + "]";
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+
+ // Display the success or failure info
+ if (startedVolumes.size() == 0) { // No volume(s) started successfully
+ showErrorDialog(actionDesc, "Volume(s) " + failedVolumes + " could not be started!"
+ + CoreConstants.NEWLINE + "Error: [" + errorMessage + "]");
+ } else {
+ String info = "Volume(s) " + startedVolumes + " started successfully!";
+ if (!errorMessage.equals("")) {
+ info += CoreConstants.NEWLINE + CoreConstants.NEWLINE + "Volumes " + failedVolumes
+ + " failed to start! [" + errorMessage + "]";
+ }
+ if (selectedVolumes.size() == startedVolumes.size()) {
+ showInfoDialog(actionDesc, info);
+ } else {
+ showWarningDialog(actionDesc, info);
+ }
+ }
+ }
+
+ private void collectVolumeNames() {
+ selectedVolumeNames.clear();
+ offlineVolumeNames.clear();
+ for (Volume volume : selectedVolumes) {
+ selectedVolumeNames.add(volume.getName());
+ if (volume.getStatus() == VOLUME_STATUS.OFFLINE) {
+ offlineVolumeNames.add(volume.getName());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ Set<Volume> selectedVolumeNames = GUIHelper.getInstance().getSelectedEntities(getWindow(), Volume.class);
+ selectedVolumes.clear();
+ if (selectedVolumeNames == null || selectedVolumeNames.isEmpty()) {
+ super.selectionChanged(action, selection);
+ if (selectedEntity instanceof Volume) {
+ selectedVolumes.add((Volume) selectedEntity);
+ }
+ } else {
+ selectedVolumes.addAll(selectedVolumeNames); //TODO reverse the collection to maintain the selected order
+ }
+
+ action.setEnabled(false);
+ // To enable the action
+ for (Volume volume : selectedVolumes) {
+ if (volume.getStatus() == VOLUME_STATUS.OFFLINE) {
+ action.setEnabled(true);
+ break;// If find an online volume, enable the action
+ }
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopTaskAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopTaskAction.java
new file mode 100644
index 00000000..e5ba017d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopTaskAction.java
@@ -0,0 +1,46 @@
+package org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+
+
+public class StopTaskAction extends AbstractActionDelegate {
+ private TaskInfo taskInfo;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ @Override
+ protected void performAction(final IAction action) {
+ final String actionDesc = action.getDescription();
+
+ try {
+ new TasksClient().stopTask(taskInfo.getName());
+ // On successful stop clear from the task list
+ modelManager.removeTask(taskInfo);
+ action.setEnabled(false); // TODO disable other task buttons
+ } catch (Exception e) {
+ showErrorDialog(actionDesc,
+ "Task [" + taskInfo.getDescription() + "] could not be Stopped! Error: [" + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ action.setEnabled(false);
+ if (selectedEntity instanceof TaskInfo) {
+ taskInfo = (TaskInfo) selectedEntity;
+ action.setEnabled(taskInfo.getStopSupported()
+ && (taskInfo.getStatus().getCode() == Status.STATUS_CODE_PAUSE
+ || taskInfo.getStatus().getCode() == Status.STATUS_CODE_RUNNING));
+ }
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopVolumeAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopVolumeAction.java
new file mode 100644
index 00000000..e1b67c1d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/StopVolumeAction.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+
+
+public class StopVolumeAction extends AbstractMonitoredActionDelegate {
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private List<Volume> selectedVolumes = new ArrayList<Volume>();
+ private List<String> selectedVolumeNames = new ArrayList<String>();
+ private List<String> onlineVolumeNames = new ArrayList<String>();
+ private List<String> stoppedVolumes = new ArrayList<String>();
+ private List<Volume> failedVolumes = new ArrayList<Volume>();
+ private String errorMessage = null;
+
+ @Override
+ protected void performAction(final IAction action, IProgressMonitor monitor) {
+ collectVolumeNames();
+
+ if (onlineVolumeNames.size() == 0) {
+ showWarningDialog(action.getDescription(), "Volumes " + selectedVolumeNames + " already stopped!");
+ return; // Volumes already stopped, Don't do anything.
+ }
+
+ Integer userAction = new MessageDialog(getShell(), "Stop Volume", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16), "Are you sure you want to stop the following volumes?"
+ + CoreConstants.NEWLINE + onlineVolumeNames, MessageDialog.QUESTION,
+ new String[] { "No", "Yes" }, -1).open();
+
+ if (userAction <= 0) { // user select cancel or pressed escape key
+ return;
+ }
+
+ List<String> cifsVolumes = GlusterDataModelManager.getInstance().getCifsEnabledVolumeNames(selectedVolumes);
+ List<String> offlineServers = GlusterDataModelManager.getInstance().getOfflineServers();
+ // One or more servers are offline, Show warning if cifs is enabled
+ if (cifsVolumes != null && cifsVolumes.size() > 0 && offlineServers != null && offlineServers.size() > 0) {
+ userAction = new MessageDialog(getShell(), "CIFS configuration", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16),
+ "Performing CIFS updates when one or more servers are offline can trigger "
+ + "inconsistent behavior for CIFS accesses in the cluster." + CoreConstants.NEWLINE
+ + "Are you sure you want to continue?", MessageDialog.QUESTION,
+ new String[] { "No", "Yes" }, -1).open();
+ if (userAction != 1) {
+ return; // Do not stop volume services
+ }
+ }
+
+ stopVolumes(selectedVolumes, false, monitor);
+
+ // Check for errors, trying to force stop in case of errors
+ checkForErrors(action, monitor, true);
+ }
+
+ private void checkForErrors(final IAction action, IProgressMonitor monitor, boolean tryForceStop) {
+ String message = null;
+ if (stoppedVolumes.size() == 0) { // No volume(s) stopped successfully
+ message = "Volume(s) " + failedVolumes + " could not be stopped! " + CoreConstants.NEWLINE
+ + "Error: [" + errorMessage + "]";
+ if(tryForceStop) {
+ forceStopVolumes(action.getDescription(), message + CoreConstants.NEWLINE
+ + "Do you want to stop forcefully?", monitor);
+ // check for errors without trying to force stop in case of errors
+ checkForErrors(action, monitor, false);
+ return;
+ } else {
+ showErrorDialog(action.getDescription(), message);
+ return;
+ }
+ } else {
+ message = "Volume(s) " + stoppedVolumes + " stopped successfully!";
+ if (!errorMessage.isEmpty()) {
+ if (failedVolumes.size() > 0) {
+ message = message + CoreConstants.NEWLINE + CoreConstants.NEWLINE + "Volume(s) "
+ + failedVolumes + " could not be stopped! [" + errorMessage + "]";
+ if(tryForceStop) {
+ forceStopVolumes(action.getDescription(), message + CoreConstants.NEWLINE
+ + "Do you want to stop forcefully?", monitor);
+ // check for errors without trying to force stop in case of errors
+ checkForErrors(action, monitor, false);
+ return;
+ }
+ } else { // Stop volume success, but post stop volume fails, append the error message
+ message += CoreConstants.NEWLINE + CoreConstants.NEWLINE + errorMessage;
+ }
+ }
+
+ if (errorMessage.isEmpty()) {
+ showInfoDialog(action.getDescription(), message);
+ } else {
+ showWarningDialog(action.getDescription(), message);
+ }
+ }
+ }
+
+ private void forceStopVolumes(String actionDesc, String message, IProgressMonitor monitor) {
+ boolean forceStop = showConfirmDialog(actionDesc, message);
+ if (!forceStop) {
+ return;
+ }
+ stopVolumes(failedVolumes, true, monitor);
+ }
+
+ private void stopVolumes(List<Volume> volumes, Boolean force, IProgressMonitor monitor) {
+ VolumesClient vc = new VolumesClient();
+ Volume newVolume = new Volume();
+ stoppedVolumes.clear();
+ failedVolumes.clear();
+ errorMessage = "";
+
+ monitor.beginTask("Stopping Selected Volumes...", volumes.size());
+ // Stopping of a volume results in changes to the model, and ultimately updates the "selectedVolumes" list,
+ // over which we are iterating, thus resulting in ConcurrentModificationException. To avoid this, we iterate
+ // over an array obtained from the list.
+ for (Volume volume : volumes.toArray(new Volume[0])) {
+ if(monitor.isCanceled()) {
+ break;
+ }
+
+ if (volume.getStatus() == VOLUME_STATUS.OFFLINE) {
+ monitor.worked(1);
+ continue; // skip if already stopped
+ }
+ try {
+ monitor.setTaskName("Stopping volume [" + volume.getName() + "]");
+ vc.stopVolume(volume.getName(), force);
+ stoppedVolumes.add(volume.getName());
+ modelManager.updateVolumeStatus(volume, VOLUME_STATUS.OFFLINE);
+ } catch (Exception e) {
+ // If any post volume stop activity failed, update the volume status
+ if (vc.getVolume(volume.getName()).getStatus() == VOLUME_STATUS.OFFLINE) {
+ // stop volume succeed, so add it to stoppedVolumes
+ stoppedVolumes.add(volume.getName());
+ modelManager.updateVolumeStatus(volume, VOLUME_STATUS.OFFLINE);
+ errorMessage += "Volume [" + volume.getName() + "] stopped, but following error occured: ["
+ + e.getMessage() + "]";
+ } else {
+ failedVolumes.add(volume);
+ errorMessage += "[" + volume.getName() + "] : " + e.getMessage() + CoreConstants.NEWLINE;
+ }
+ }
+
+ // Update the model by fetching latest volume info (NOT JUST STATUS)
+ try {
+ modelManager.refreshVolumeData(volume);
+ } catch (Exception e) {
+ errorMessage += "Failed to update volume info on UI. [" + e.getMessage() + "]";
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+ }
+
+ private void collectVolumeNames() {
+ selectedVolumeNames.clear();
+ onlineVolumeNames.clear();
+ for (Volume volume : selectedVolumes) {
+ selectedVolumeNames.add(volume.getName());
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ onlineVolumeNames.add(volume.getName());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.gluster.storage.management.console.actions.AbstractActionDelegate#selectionChanged(org.eclipse.jface.action.IAction
+ * , org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ Set<Volume> selectedVolumeNames = GUIHelper.getInstance().getSelectedEntities(getWindow(), Volume.class);
+ selectedVolumes.clear();
+ if (selectedVolumeNames == null || selectedVolumeNames.isEmpty()) {
+ super.selectionChanged(action, selection);
+ if (selectedEntity instanceof Volume) {
+ selectedVolumes.add((Volume) selectedEntity);
+ }
+ } else {
+ selectedVolumes.addAll(selectedVolumeNames); //TODO reverse the collection to maintain the selected order
+ }
+
+ action.setEnabled(false);
+ // To enable the action
+ for (Volume volume : selectedVolumes) {
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ action.setEnabled(true);
+ break; // If find an online volume, enable the action
+ }
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/SupportAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/SupportAction.java
new file mode 100644
index 00000000..9b698df9
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/SupportAction.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.console.dialogs.GlusterSupportDialog;
+
+
+/**
+ *
+ */
+public class SupportAction extends AbstractActionDelegate {
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.actions.AbstractActionDelegate#performAction(org.eclipse.jface.action.IAction)
+ */
+ @Override
+ protected void performAction(IAction action) {
+ GlusterSupportDialog dialog = new GlusterSupportDialog(getShell());
+ dialog.create();
+ dialog.getShell().setSize(770, 430);
+ dialog.open();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
+ */
+ @Override
+ public void dispose() {
+
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TerminalAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TerminalAction.java
new file mode 100644
index 00000000..433bff69
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TerminalAction.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+/**
+ *
+ */
+public class TerminalAction extends AbstractActionDelegate {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
+ */
+ @Override
+ public void dispose() {
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.actions.AbstractActionDelegate#performAction(org.eclipse.jface.action.IAction)
+ */
+ @Override
+ protected void performAction(IAction action) {
+ GUIHelper.getInstance().showTerminalView();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TestPopupMenuAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TestPopupMenuAction.java
new file mode 100644
index 00000000..dfb2af2f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/TestPopupMenuAction.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+public class TestPopupMenuAction implements IObjectActionDelegate {
+
+ private Shell shell;
+
+ /**
+ * Constructor for Action1.
+ */
+ public TestPopupMenuAction() {
+ super();
+ }
+
+ /**
+ * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
+ */
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ shell = targetPart.getSite().getShell();
+ }
+
+ /**
+ * @see IActionDelegate#run(IAction)
+ */
+ public void run(IAction action) {
+ MessageDialog.openInformation(
+ shell,
+ "glustersp-gui",
+ "New Action was executed.");
+ }
+
+ /**
+ * @see IActionDelegate#selectionChanged(IAction, ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/VolumeLogRotateAction.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/VolumeLogRotateAction.java
new file mode 100644
index 00000000..7477358c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/actions/VolumeLogRotateAction.java
@@ -0,0 +1,64 @@
+package org.gluster.storage.management.console.actions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.VolumeBricksView;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+
+
+
+public class VolumeLogRotateAction extends AbstractActionDelegate {
+
+ private Volume volume;
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private Set<Brick> bricks;
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ protected void performAction(IAction action) {
+ final String actionDesc = action.getDescription();
+ List<String> selectedBricks = new ArrayList<String>();
+ boolean confirmed = showConfirmDialog(actionDesc,
+ "Are you sure you want to Rotate logs for volume [" + volume.getName() + "] ? ");
+ if (!confirmed) {
+ return;
+ }
+
+ if (bricks != null) {
+ selectedBricks = GlusterCoreUtil.getQualifiedBrickList(bricks);
+ }
+ try {
+ new VolumesClient().volumeLogRotate(volume.getName(), selectedBricks);
+ showInfoDialog(actionDesc, "Volume logs for [" + volume.getName() + "] rotated successfully!");
+ } catch (Exception e) {
+ showErrorDialog(actionDesc, "Volume [" + volume.getName() + "] log rotation failed! Error: [" + e.getMessage() + "]");
+ }
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ volume = guiHelper.getSelectedEntity(window, Volume.class);
+
+ if (volume != null) {
+ // a volume is selected on navigation tree. Let's check if the currently open view is volume bricks view
+ IWorkbenchPart view = guiHelper.getActiveView();
+ if (view instanceof VolumeBricksView) {
+ // volume bricks view is open. check if any brick is selected
+ bricks = GUIHelper.getInstance().getSelectedEntities(getWindow(), Brick.class);
+ }
+ }
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickPage.java
new file mode 100644
index 00000000..df42f12a
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickPage.java
@@ -0,0 +1,171 @@
+/**
+ * AddDiskPage.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+
+import com.richclientgui.toolbox.duallists.DualListComposite.ListContentChangedListener;
+import com.richclientgui.toolbox.duallists.IRemovableContentProvider;
+
+/**
+ * @author root
+ *
+ */
+public class AddBrickPage extends WizardPage {
+ private List<Device> availableDevices = new ArrayList<Device>();
+ private List<Device> selectedDevices = new ArrayList<Device>();
+ private Volume volume = null;
+ private BricksSelectionPage page = null;
+
+
+ public static final String PAGE_NAME = "add.disk.volume.page";
+
+ /**
+ * @param pageName
+ */
+ protected AddBrickPage(Volume volume) {
+ super(PAGE_NAME);
+ this.volume = volume;
+ setTitle("Add Brick");
+
+ String description = "Add bricks to [" + volume.getName() + "] ";
+ if ( volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_REPLICATE) {
+ description += "(in multiples of " + volume.getReplicaCount() + ")";
+ } else if (volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ description += "(in multiples of " + volume.getStripeCount() + ")";
+ }
+ setDescription(description);
+
+ availableDevices = getAvailableDevices(volume);
+
+ setPageComplete(false);
+ setErrorMessage("Please select bricks to be added to the volume [" + volume.getName() +"]");
+ }
+
+
+ private boolean isDeviceUsed(Volume volume, Device device){
+ for (Brick volumeBrick : volume.getBricks()) {
+ if ( device.getQualifiedBrickName(volume.getName()).equals(volumeBrick.getQualifiedName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected List<Device> getAvailableDevices(Volume volume) {
+ List<Device> availableDevices = new ArrayList<Device>();
+ for (Device device : GlusterDataModelManager.getInstance().getReadyDevicesOfAllServers()) {
+ if ( ! isDeviceUsed(volume, device) ) {
+ availableDevices.add(device);
+ }
+ }
+ return availableDevices;
+ }
+
+ public Set<Device> getChosenDevices() {
+ return new HashSet<Device>(page.getChosenDevices());
+ }
+
+ public Set<Brick> getChosenBricks( String volumeName ) {
+ return page.getChosenBricks(volumeName);
+ }
+
+ private boolean isValidDiskSelection(int diskCount) {
+ if ( diskCount == 0) {
+ return false;
+ }
+ switch (volume.getVolumeType()) {
+ case DISTRIBUTED_REPLICATE:
+ return (diskCount % volume.getReplicaCount() == 0);
+ case DISTRIBUTED_STRIPE:
+ return (diskCount % volume.getStripeCount() == 0);
+ }
+ return true;
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent) {
+ getShell().setText("Add Brick");
+ List<Device> chosenDevices = new ArrayList<Device>(); // or volume.getDisks();
+
+ page = new BricksSelectionPage(parent, SWT.NONE, availableDevices, chosenDevices, volume.getName());
+ page.addDiskSelectionListener(new ListContentChangedListener<Device>() {
+ @Override
+ public void listContentChanged(IRemovableContentProvider<Device> contentProvider) {
+ List<Device> newChosenDevices = page.getChosenDevices();
+
+ // validate chosen disks
+ if(isValidDiskSelection(newChosenDevices.size())) {
+ clearError();
+ } else {
+ setError();
+ }
+ }
+ });
+ setControl(page);
+ }
+
+ private void setError() {
+ String errorMessage = null;
+ if ( volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTE) {
+ errorMessage = "Please select at least one brick!";
+ } else if( volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_REPLICATE) {
+ errorMessage = "Please select bricks in multiples of " + volume.getReplicaCount();
+ } else {
+ errorMessage = "Please select bricks in multiples of " + volume.getStripeCount();
+ }
+
+ setPageComplete(false);
+ setErrorMessage(errorMessage);
+ }
+
+ private void clearError() {
+ setErrorMessage(null);
+ setPageComplete(true);
+ }
+
+ public BricksSelectionPage getDialogPage() {
+ return this.page;
+ }
+
+ public void setPageComplete() {
+
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickWizard.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickWizard.java
new file mode 100644
index 00000000..da40f1d9
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/AddBrickWizard.java
@@ -0,0 +1,96 @@
+/**
+ * AddDiskWizard.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.utils.StringUtil;
+
+
+/**
+ *
+ */
+public class AddBrickWizard extends Wizard {
+ private AddBrickPage page;
+ private Volume volume;
+
+ public AddBrickWizard(Volume volume) {
+ setWindowTitle("Gluster Management Console - Add Brick");
+ setHelpAvailable(false); // TODO: Introduce wizard help
+ this.volume = volume;
+ }
+
+ public void addPages() {
+ page = new AddBrickPage(volume);
+ addPage(page);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish() {
+ Set<Brick> bricks = page.getChosenBricks(volume.getName());
+ VolumesClient volumeClient = new VolumesClient();
+ try {
+ Set<String> brickList = getBrickList(bricks);
+
+ volumeClient.addBricks(volume.getName(), brickList);
+
+ // Update model with new bricks in the volume
+ GlusterDataModelManager.getInstance().addBricks(volume, bricks);
+
+ MessageDialog.openInformation(getShell(), "Add brick(s) to Volume", "Volume [" + volume.getName()
+ + "] is expanded with bricks [" + StringUtil.collectionToString(brickList, ", ") + "]");
+ return true;
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), "Add brick(s) to Volume", e.getMessage());
+ return false;
+ }
+ }
+
+ private Set<String> getBrickList(Set<Brick> bricks) {
+ Set<String> brickList = new HashSet<String>();
+ for(Brick brick : bricks) {
+ brickList.add(brick.getServerName() + ":" + brick.getBrickDirectory());
+ }
+ return brickList;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.wizard.Wizard#canFinish()
+ */
+ @Override
+ public boolean canFinish() {
+ return super.canFinish() && page.isPageComplete();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/BricksSelectionPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/BricksSelectionPage.java
new file mode 100644
index 00000000..99f6d201
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/BricksSelectionPage.java
@@ -0,0 +1,336 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.TableLabelProviderAdapter;
+import org.gluster.storage.management.console.utils.EntityViewerFilter;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+import com.richclientgui.toolbox.duallists.CustomTableDualListComposite;
+import com.richclientgui.toolbox.duallists.DualListComposite.ListContentChangedListener;
+import com.richclientgui.toolbox.duallists.IRemovableContentProvider;
+import com.richclientgui.toolbox.duallists.RemovableContentProvider;
+import com.richclientgui.toolbox.duallists.TableColumnData;
+
+public class BricksSelectionPage extends Composite {
+ private enum DISK_TABLE_COLUMN_INDICES {
+ SERVER, BRICK_DIRECTORY, FREE_SPACE, TOTAL_SPACE
+ }
+
+ private static final String[] DISK_TABLE_COLUMNS_NAMES = { "Server", "Brick Directory", "Free Space (GB)",
+ "Total Space (GB)" };
+
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private CustomTableDualListComposite<Device> dualTableViewer;
+ private Text filterText;
+ // This list keeps track of the order of the disks as user changes the same by clicking on up/down arrow buttons
+ private List<Device> chosenDevices = new ArrayList<Device>();
+
+ private IRemovableContentProvider<Device> chosenBricksContentProvider;
+
+ private Button btnUp;
+
+ private Button btnDown;
+
+ public BricksSelectionPage(final Composite parent, int style, List<Device> allDevices, List<Device> selectedDevices,
+ String volumeName) {
+ super(parent, style);
+
+ createPage(allDevices, selectedDevices, volumeName);
+
+ parent.layout();
+ }
+
+ public void addDiskSelectionListener(ListContentChangedListener<Device> listener) {
+ dualTableViewer.addChosenListChangedSelectionListener(listener);
+ }
+
+ private TableLabelProviderAdapter getDiskLabelProvider(final String volumeName) {
+ return new TableLabelProviderAdapter() {
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Device)) {
+ return null;
+ }
+
+ Device device = (Device) element;
+ return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? device.getServerName()
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.BRICK_DIRECTORY.ordinal() ? device.getMountPoint()
+ + "/" + volumeName
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal() ? NumberUtil
+ .formatNumber((device.getFreeSpace() / 1024))
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal() ? NumberUtil
+ .formatNumber((device.getSpace() / 1024)) : "Invalid");
+ }
+ };
+ }
+
+ private int indexOf(List<Disk> disks, Disk searchDisk) {
+ for (Disk disk : disks) {
+ if (disk.getQualifiedName().equals(searchDisk.getQualifiedName())) {
+ return disks.indexOf(disk);
+ }
+ }
+ return -1;
+ }
+
+ private void createPage(List<Device> allDevice, List<Device> selectedDevice, String volumeName) {
+ setupPageLayout();
+
+ filterText = guiHelper.createFilterText(this);
+ new Label(this, SWT.NONE);
+
+ createDualTableViewer(allDevice, selectedDevice, volumeName);
+ createFilter(filterText, false); // attach filter text to the dual table viewer for auto-filtering
+
+ Composite buttonContainer = new Composite(this, SWT.NONE);
+ buttonContainer.setLayout(new GridLayout(1, false));
+ GridData buttonContainerData = new GridData(SWT.FILL, SWT.CENTER, true, true);
+ buttonContainerData.minimumWidth = 40;
+ buttonContainer.setLayoutData(buttonContainerData);
+
+ btnUp = new Button(buttonContainer, SWT.PUSH);
+ GridData btnUpData = new GridData(SWT.LEFT, SWT.BOTTOM, true, false);
+ btnUpData.minimumWidth = 30;
+ btnUp.setLayoutData(btnUpData);
+ btnUp.setImage(guiHelper.getImage(IImageKeys.ARROW_UP_16x16));
+ btnUp.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ chosenDevices = getChosenDevices();
+ List<Device> selectedDevices = getSelectedChosenDevices();
+
+ chosenBricksContentProvider.removeElements(chosenDevices);
+ for (Device device : selectedDevices) {
+ int index = chosenDevices.indexOf(device);
+ Device deviceAbove = chosenDevices.get(index - 1);
+ chosenDevices.set(index - 1, device);
+ chosenDevices.set(index, deviceAbove);
+ }
+ chosenBricksContentProvider.addElements(chosenDevices);
+ dualTableViewer.refreshChosenViewer();
+ updateButtons();
+ }
+ });
+
+ btnDown = new Button(buttonContainer, SWT.PUSH);
+ GridData btnDownData = new GridData(SWT.LEFT, SWT.TOP, true, false);
+ btnDownData.minimumWidth = 30;
+ btnDown.setLayoutData(btnDownData);
+ btnDown.setImage(guiHelper.getImage(IImageKeys.ARROW_DOWN_16x16));
+ btnDown.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+
+ chosenDevices = getChosenDevices();
+ List<Device> selectedDevices = getSelectedChosenDevices();
+
+ chosenBricksContentProvider.removeElements(chosenDevices);
+ for (Device disk : selectedDevices) {
+ int index = chosenDevices.indexOf(disk);
+ Device deviceBelow = chosenDevices.get(index + 1);
+ chosenDevices.set(index + 1, disk);
+ chosenDevices.set(index, deviceBelow);
+ }
+ chosenBricksContentProvider.addElements(chosenDevices);
+ dualTableViewer.refreshChosenViewer();
+ updateButtons();
+
+ }
+ });
+ }
+
+ private List<Device> getSelectedChosenDevices() {
+ TableItem[] selectedItems = dualTableViewer.getChosenTable().getSelection();
+ List<Device> selectedDevices = new ArrayList<Device>();
+ for (TableItem item : selectedItems) {
+ selectedDevices.add((Device) item.getData());
+ }
+ return selectedDevices;
+ }
+
+ private void createFilter(final Text filterText, boolean caseSensitive) {
+ final String initialFilterString = filterText.getText();
+
+ final EntityViewerFilter filter = new EntityViewerFilter(initialFilterString, caseSensitive);
+ // On every keystroke inside the text field, update the filter string
+ filterText.addKeyListener(new KeyAdapter() {
+ private String filterString = initialFilterString;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ String enteredString = filterText.getText();
+ if (enteredString.equals(filterString)) {
+ // Filter string has not changed. don't do anything
+ return;
+ }
+
+ // Update filter string
+ filterString = enteredString;
+ filter.setFilterString(filterString);
+
+ // Refresh viewer with newly filtered content
+ dualTableViewer.refreshAvailableViewer();
+ dualTableViewer.refreshChosenViewer();
+ }
+ });
+
+ dualTableViewer.setAvailableViewerFilter(filter);
+ dualTableViewer.setChosenViewerFilter(filter);
+ }
+
+ private void createDualTableViewer(List<Device> allDevices, List<Device> selectedDevices, String volumeName) {
+ TableColumnData[] columnData = createColumnData();
+ ITableLabelProvider diskLabelProvider = getDiskLabelProvider(volumeName);
+
+ dualTableViewer = new CustomTableDualListComposite<Device>(this, SWT.NONE, columnData, columnData);
+
+ dualTableViewer.setViewerLabels("Available:", "Selected:");
+
+ dualTableViewer.setAvailableTableLinesVisible(false);
+ dualTableViewer.setAvailableTableHeaderVisible(true);
+ dualTableViewer.setAvailableContentProvider(new RemovableContentProvider<Device>(getAvailableDevice(allDevices,
+ selectedDevices)));
+ dualTableViewer.setAvailableLabelProvider(diskLabelProvider);
+
+ dualTableViewer.setChosenTableLinesVisible(true);
+ dualTableViewer.setChosenTableHeaderVisible(true);
+
+ chosenBricksContentProvider = new RemovableContentProvider<Device>(selectedDevices);
+ dualTableViewer.setChosenContentProvider(chosenBricksContentProvider);
+ dualTableViewer.setChosenLabelProvider(diskLabelProvider);
+
+ dualTableViewer.getChosenTable().addSelectionListener(new SelectionAdapter() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateButtons();
+ }
+ });
+ }
+
+ private void updateButtons() {
+ btnUp.setEnabled(true);
+ btnDown.setEnabled(true);
+ List<Device> selectedChosenDevices = getSelectedChosenDevices();
+ List<Device> chosenDevices = getChosenDevices();
+ for (Device device : selectedChosenDevices) {
+ int index = chosenDevices.indexOf(device);
+ if (index == 0) {
+ btnUp.setEnabled(false);
+ }
+ if (index == chosenDevices.size() - 1) {
+ btnDown.setEnabled(false);
+ }
+ }
+ }
+
+ /**
+ * @param allDevices
+ * @param selectedDevices
+ * @return
+ */
+ private List<Device> getAvailableDevice(List<Device> allDevices, List<Device> selectedDevices) {
+ List<Device> availableDevices = new ArrayList<Device>();
+ for (Device device : allDevices) {
+ if (!selectedDevices.contains(device)) {
+ availableDevices.add(device);
+ }
+ }
+ return availableDevices;
+ }
+
+ private TableColumnData[] createColumnData() {
+ DISK_TABLE_COLUMN_INDICES[] columns = DISK_TABLE_COLUMN_INDICES.values();
+ TableColumnData[] columnData = new TableColumnData[columns.length];
+ int columnNum;
+ for (DISK_TABLE_COLUMN_INDICES column : columns) {
+ columnNum = column.ordinal();
+ columnData[columnNum] = new TableColumnData(columnNum, DISK_TABLE_COLUMNS_NAMES[columnNum], 100);
+ }
+ return columnData;
+ }
+
+ private void setupPageLayout() {
+ final GridLayout layout = new GridLayout(2, false);
+ layout.verticalSpacing = 10;
+ layout.marginTop = 10;
+ setLayout(layout);
+
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ }
+
+ public List<Device> getChosenDevices() {
+ Object[] devicesArr = chosenBricksContentProvider.getElements(dualTableViewer);
+ if (devicesArr != null) {
+ List<Device> devices = new ArrayList<Device>();
+ for (Object device : devicesArr) {
+ devices.add((Device) device);
+ }
+ return devices;
+ }
+ return null;
+ }
+
+ public Set<Brick> getChosenBricks(String volumeName) {
+ Object[] bricksArr = chosenBricksContentProvider.getElements(dualTableViewer);
+
+ if (bricksArr != null) {
+ Set<Brick> bricks = new HashSet<Brick>();
+ for (Object device : bricksArr) {
+ bricks.add(new Brick(((Device) device).getServerName(), BRICK_STATUS.ONLINE, ((Device) device)
+ .getMountPoint() + "/" + volumeName)); // Assumption mount point is not having trailing "/"
+ }
+ return bricks;
+ }
+ return null;
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ChangePasswordDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ChangePasswordDialog.java
new file mode 100644
index 00000000..09b4b08c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ChangePasswordDialog.java
@@ -0,0 +1,284 @@
+/**
+ * ChangePasswordDialog.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.beans.PojoProperties;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.client.UsersClient;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.validators.StringRequiredValidator;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.ConnectionDetails;
+
+
+public class ChangePasswordDialog extends Dialog {
+ public static final int RETURN_CODE_ERROR = 2;
+ private Text oldPassword;
+ private Text newPassword;
+ private Text confirmPassword;
+ private Button okButton;
+
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Composite composite;
+
+ private final ConnectionDetails connectionDetails = new ConnectionDetails("gluster", "");
+
+ public ChangePasswordDialog(Shell shell) {
+ super(shell);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Gluster Management Console");
+ addEscapeListener(newShell);
+ }
+
+ private void addEscapeListener(Shell shell) {
+ shell.addTraverseListener(new TraverseListener() {
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ cancelPressed();
+ }
+ }
+ });
+ }
+
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+ private void configureDialogLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.numColumns = 2;
+ layout.marginLeft = 20;
+ layout.marginRight = 20;
+ layout.marginTop = 20;
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 20;
+ }
+
+ // ------------------------------------------
+
+ private void createLabel(Composite composite, String label) {
+ Label passwordLabel = new Label(composite, SWT.NONE);
+ passwordLabel.setText(label);
+ passwordLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private Text createPasswordText(Composite composite) {
+ Text field = new Text(composite, SWT.BORDER | SWT.PASSWORD);
+ GridData layoutData = new GridData(SWT.FILL, GridData.FILL, true, false);
+ layoutData.widthHint = convertWidthInCharsToPixels(32);
+ field.setLayoutData(layoutData);
+ return field;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ // parent.setBackgroundImage(guiHelper.getImage(IImageKeys.DIALOG_SPLASH_IMAGE));
+ parent.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ composite = (Composite) super.createDialogArea(parent);
+ configureDialogLayout(composite);
+
+ createLabel(composite, "Old Password:");
+ oldPassword = createPasswordText(composite);
+
+ createLabel(composite, "New Password:");
+ newPassword = createPasswordText(composite);
+
+ createLabel(composite, "Confirm Password:");
+ confirmPassword = createPasswordText(composite);
+
+ createListeners();
+
+ return composite;
+ }
+
+ /**
+ *
+ */
+ private void createListeners() {
+ ModifyListener listener = new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ updateButtonStatus();
+ }
+ };
+
+ oldPassword.addModifyListener(listener);
+ newPassword.addModifyListener(listener);
+ confirmPassword.addModifyListener(listener);
+ }
+
+ private void updateButtonStatus() {
+ String oldPwd = oldPassword.getText();
+ String newPwd = newPassword.getText();
+ String confirmPwd = confirmPassword.getText();
+ if(oldPwd.isEmpty() || newPwd.isEmpty() || confirmPwd.isEmpty()) {
+ okButton.setEnabled(false);
+ return;
+ }
+
+ if(!newPwd.equals(confirmPwd)) {
+ okButton.setEnabled(false);
+ return;
+ }
+
+ if (confirmPwd.equals(CoreConstants.DEFAULT_PASSWORD) || isContainsWhiteSpace(confirmPwd)) {
+ okButton.setEnabled(false);
+ return;
+ }
+
+ if (newPwd.length() < 4 ) { // Minimum password length is 4
+ okButton.setEnabled(false);
+ return;
+ }
+
+ okButton.setEnabled(true);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ okButton = createButton(parent, IDialogConstants.OK_ID, "&Change", true);
+ okButton.setEnabled(false);
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+
+ setupDataBinding();
+ }
+
+ public boolean isContainsWhiteSpace(String text) {
+ return text.matches(".*[\\s\\\\].*"); // White space or backslash
+ }
+
+ public class ConfirmPasswordValidator extends StringRequiredValidator {
+ public ConfirmPasswordValidator(String errorText, ControlDecoration controlDecoration, Control linkedControl) {
+ super(errorText, controlDecoration, linkedControl);
+ }
+
+ @Override
+ public IStatus validate(Object value) {
+
+ IStatus status = super.validate(value);
+ if (status.isOK()) {
+ String errMsg = null;
+ if (errMsg == null && isContainsWhiteSpace( newPassword.getText())) {
+ errMsg = "Password should not contain space or back slash characters";
+ }
+
+ if (!value.equals(newPassword.getText())) {
+ errMsg = "Passwords mismatched";
+ }
+
+ if (errMsg == null && value.equals(CoreConstants.DEFAULT_PASSWORD)) {
+ errMsg = "New password should not be a default password";
+ }
+
+ if(errMsg != null) {
+ controlDecoration.setDescriptionText(errMsg);
+ controlDecoration.show();
+ linkedControl.setEnabled(false);
+ return ValidationStatus.error(errMsg);
+ }
+ }
+ return status;
+ }
+ };
+
+ private void setupDataBinding() {
+ DataBindingContext dataBindingContext = new DataBindingContext(SWTObservables.getRealm(Display.getCurrent()));
+ UpdateValueStrategy passwordBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+ UpdateValueStrategy newPwdBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+ UpdateValueStrategy confirmPwdBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+
+ // The Validator shows error decoration and disables OK button on
+ // validation failure
+ passwordBindingStrategy.setBeforeSetValidator(new StringRequiredValidator("Please enter old password!",
+ guiHelper.createErrorDecoration(oldPassword), null));
+
+ dataBindingContext.bindValue(WidgetProperties.text(SWT.Modify).observe(oldPassword),
+ PojoProperties.value("password").observe(connectionDetails), passwordBindingStrategy,
+ passwordBindingStrategy);
+
+ newPwdBindingStrategy.setBeforeSetValidator(new StringRequiredValidator("Please enter new password!", guiHelper
+ .createErrorDecoration(newPassword), null));
+
+ dataBindingContext.bindValue(WidgetProperties.text(SWT.Modify).observe(newPassword),
+ PojoProperties.value("newPassword").observe(connectionDetails), newPwdBindingStrategy,
+ newPwdBindingStrategy);
+
+ confirmPwdBindingStrategy.setBeforeSetValidator(new ConfirmPasswordValidator("Please enter confirm password!",
+ guiHelper.createErrorDecoration(confirmPassword), null));
+
+ dataBindingContext.bindValue(WidgetProperties.text(SWT.Modify).observe(confirmPassword),
+ PojoProperties.value("confirmNewPassword").observe(connectionDetails), confirmPwdBindingStrategy,
+ confirmPwdBindingStrategy);
+ }
+
+ protected void okPressed() {
+ String user = connectionDetails.getUserId();
+ String oldPassword = connectionDetails.getPassword();
+ String newPassword = connectionDetails.getNewPassword();
+
+ UsersClient usersClient = new UsersClient();
+ try {
+ usersClient.changePassword(user, oldPassword, newPassword);
+ MessageDialog.openInformation(getShell(), "Change password", "Password changed successfully!");
+ this.close();
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), "Change password Failed", e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ClusterSelectionDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ClusterSelectionDialog.java
new file mode 100644
index 00000000..44b9e963
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ClusterSelectionDialog.java
@@ -0,0 +1,474 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.console.Activator;
+import org.gluster.storage.management.console.ConsoleConstants;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+/**
+ * Cluster selection dialog, which prompts for the cluster name to be managed
+ */
+public class ClusterSelectionDialog extends Dialog {
+ private static final String MESSAGE_SELECT_CLUSTER = "Select the Cluster you want to manage in this session.";
+ private static final String MESSAGE_CREATE_CLUSTER = "Create an empty Cluster and start adding servers to it.";
+ private static final String MESSAGE_REGISTER_CLUSTER = "Register an existing Cluster with the Management Gateway and start managing it using the Management Console.";
+
+ protected enum CLUSTER_MODE { SELECT, CREATE, REGISTER };
+
+ private Combo clusterNameCombo = null;
+ private Text newClusterNameText = null;
+ private Text existingClusterNameText = null;
+ private Text serverNameText = null;
+ private Button okButton;
+
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Composite composite;
+ private ControlDecoration newClusterNameErrorDecoration;
+ private ControlDecoration existingClusterNameErrorDecoration;
+ private ControlDecoration serverNameErrorDecoration;
+ private List<String> clusters;
+ private Button selectButton;
+ private Button createButton;
+ private Button registerButton;
+ private Composite clusterSelectionComposite;
+ private Composite clusterCreationComposite;
+ private Composite clusterRegisterComposite;
+ private StackLayout stackLayout;
+
+ private String clusterName;
+ private CLUSTER_MODE clusterMode;
+ private String serverName;
+ private Button dontAskAgainButton;
+ IPreferenceStore preferenceStore;
+
+ public ClusterSelectionDialog(Shell parentShell, List<String> clusters) {
+ super(parentShell);
+ this.clusters = clusters;
+ preferenceStore = Activator.getDefault().getPreferenceStore();
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Gluster Management Console - Select Cluster");
+ addEscapeListener(newShell);
+ }
+
+ private void addEscapeListener(Shell shell) {
+ shell.addTraverseListener(new TraverseListener() {
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ cancelPressed();
+ }
+ }
+ });
+ }
+
+ private void createClusterNameLabel(Composite composite) {
+ Label clusterNameLabel = new Label(composite, SWT.NONE);
+ clusterNameLabel.setText("Cluster &Name:");
+ clusterNameLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private void createClusterNameCombo(Composite composite) {
+ clusterNameCombo = new Combo(composite, SWT.READ_ONLY);
+ clusterNameCombo.setItems(clusters.toArray(new String[0]));
+ clusterNameCombo.select(0);
+
+ String clusterName = preferenceStore.getString(PreferenceConstants.P_DEFAULT_CLUSTER_NAME);
+ if(clusterName != null && !clusterName.isEmpty()) {
+ selectCluster(clusterName);
+ }
+ }
+
+ public void selectCluster(String clusterName) {
+ for(int i = 0; i < clusters.size(); i++) {
+ if(clusterNameCombo.getItem(i).equals(clusterName)) {
+ clusterNameCombo.select(i);
+ break;
+ }
+ }
+ }
+
+ private void configureDialogLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.numColumns = 3;
+ layout.marginLeft = 20;
+ layout.marginRight = 20;
+ layout.marginTop = 20;
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 20;
+ }
+
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ //parent.setBackgroundImage(guiHelper.getImage(IImageKeys.DIALOG_SPLASH_IMAGE));
+ // Makes sure that child composites inherit the same background
+ parent.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ composite = (Composite) super.createDialogArea(parent);
+ configureDialogLayout(composite);
+
+ createRadioButtons();
+ createSubComposites();
+
+ setupAutoSelectionIfRequired();
+
+ return composite;
+ }
+
+ private void setupAutoSelectionIfRequired() {
+ if (clusters.size() == 0) {
+ return;
+ }
+
+ final String clusterName = System.getProperty(ConsoleConstants.PROPERTY_AUTO_CLUSTER_NAME, null);
+ if (clusterName == null) {
+ return;
+ }
+
+ getShell().addShellListener(new ShellAdapter() {
+ @Override
+ public void shellActivated(ShellEvent e) {
+ super.shellActivated(e);
+ clusterNameCombo.setText(clusterName);
+ okPressed();
+ }
+ });
+ }
+
+
+ private void createSubComposites() {
+ Composite subComposite = new Composite(composite, SWT.NONE);
+ GridData data = new GridData();
+ data.horizontalSpan = 3;
+ subComposite.setLayoutData(data);
+ stackLayout = new StackLayout();
+ subComposite.setLayout(stackLayout);
+
+ createClusterSelectionComposite(subComposite, stackLayout);
+ createClusterCreationComposite(subComposite);
+ createClusterRegisterComposite(subComposite);
+
+ createRadioButtonListeners(subComposite);
+ if(clusters.size() > 0) {
+ selectButton.setSelection(true);
+ stackLayout.topControl = clusterSelectionComposite;
+ clusterNameCombo.setFocus();
+ } else {
+ createButton.setSelection(true);
+ stackLayout.topControl = clusterCreationComposite;
+ newClusterNameText.setFocus();
+ }
+ subComposite.layout();
+ }
+
+ private void createClusterRegisterComposite(Composite composite) {
+ clusterRegisterComposite = new Composite(composite, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ layout.horizontalSpacing = 15;
+ clusterRegisterComposite.setLayout(layout);
+
+ createClusterNameLabel(clusterRegisterComposite);
+ existingClusterNameText = createText(clusterRegisterComposite);
+ existingClusterNameText.setToolTipText("Enter a name for the cluster being registered.");
+ existingClusterNameErrorDecoration = createErrorDecoration(existingClusterNameText, "Please enter a cluster name!");
+ existingClusterNameErrorDecoration.show();
+
+ createClusterServerLabel(clusterRegisterComposite);
+ serverNameText = createText(clusterRegisterComposite);
+ serverNameText.setToolTipText("Enter host name / IP address of one of the servers of the cluster.");
+ serverNameErrorDecoration = createErrorDecoration(serverNameText, "Please enter a server name!");
+ serverNameErrorDecoration.show();
+ }
+
+ private void createClusterServerLabel(Composite composite) {
+ Label serverNameLabel = new Label(composite, SWT.NONE);
+ serverNameLabel.setText("Server Na&me:");
+ serverNameLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private void createClusterCreationComposite(Composite subComposite) {
+ clusterCreationComposite = new Composite(subComposite, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ layout.horizontalSpacing = 15;
+ clusterCreationComposite.setLayout(layout);
+
+ createClusterNameLabel(clusterCreationComposite);
+ newClusterNameText = createText(clusterCreationComposite);
+ newClusterNameText.setToolTipText("Enter name of the cluster to be created");
+ newClusterNameErrorDecoration = createErrorDecoration(newClusterNameText, "Please enter cluster name!");
+ newClusterNameErrorDecoration.show();
+ }
+
+ private Text createText(Composite parent) {
+ Text text = new Text(parent, SWT.NONE);
+ GridData layoutData = new GridData(SWT.FILL, GridData.FILL, true, false);
+ int width = convertWidthInCharsToPixels(32);
+ layoutData.widthHint = width;
+ layoutData.minimumWidth = width;
+ text.setLayoutData(layoutData);
+
+ text.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validate();
+ }
+ });
+
+ return text;
+ }
+
+ private void createClusterSelectionComposite(Composite subComposite, StackLayout stackLayout) {
+ clusterSelectionComposite = new Composite(subComposite, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ clusterSelectionComposite.setLayout(layout);
+
+ createClusterNameLabel(clusterSelectionComposite);
+ createClusterNameCombo(clusterSelectionComposite);
+ createPreferenceCheckbox(clusterSelectionComposite);
+
+ stackLayout.topControl = clusterSelectionComposite;
+ }
+
+ private void createPreferenceCheckbox(Composite composite) {
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ layoutData.verticalIndent = 5;
+ layoutData.horizontalSpan = 2;
+
+ dontAskAgainButton = new Button(composite, SWT.CHECK);
+ dontAskAgainButton.setLayoutData(layoutData);
+ dontAskAgainButton.setText("&Don't ask again");
+ dontAskAgainButton.setEnabled(true);
+ dontAskAgainButton.setSelection(false);
+ dontAskAgainButton.setToolTipText("Always manage the selected cluster without showing this dialog box."
+ + "This preference can later be changed from the \"Settings\" menu.");
+ }
+
+ private void createRadioButtons() {
+ {
+ if (clusters.size() > 0) {
+ selectButton = new Button(composite, SWT.RADIO);
+ selectButton.setText("&Select");
+ selectButton.setToolTipText(MESSAGE_SELECT_CLUSTER);
+ }
+ }
+ {
+ createButton = new Button(composite, SWT.RADIO);
+ createButton.setText("&Create");
+ createButton.setToolTipText(MESSAGE_CREATE_CLUSTER);
+ }
+ {
+ registerButton = new Button(composite, SWT.RADIO);
+ registerButton.setText("&Register");
+ registerButton.setToolTipText(MESSAGE_REGISTER_CLUSTER);
+ }
+ }
+
+ private void validate() {
+ okButton.setEnabled(false);
+
+ if(selectButton != null && selectButton.getSelection()) {
+ okButton.setEnabled(true);
+ return;
+ }
+
+ if(createButton.getSelection()) {
+ String newClusterName = newClusterNameText.getText().trim();
+ if(newClusterName.isEmpty()) {
+ newClusterNameErrorDecoration.setDescriptionText("Please enter a cluster name!");
+ newClusterNameErrorDecoration.show();
+ } else if(clusters.contains(newClusterName)) {
+ newClusterNameErrorDecoration.setDescriptionText("Cluster [" + newClusterName + "] already exists!");
+ newClusterNameErrorDecoration.show();
+ } else {
+ okButton.setEnabled(true);
+ newClusterNameErrorDecoration.hide();
+ }
+ }
+
+ if(registerButton.getSelection()) {
+ okButton.setEnabled(true);
+ String clusterName = existingClusterNameText.getText().trim();
+ if(existingClusterNameText.getText().trim().isEmpty()) {
+ existingClusterNameErrorDecoration.setDescriptionText("Please enter a cluster name!");
+ existingClusterNameErrorDecoration.show();
+ okButton.setEnabled(false);
+ } else if(clusters.contains(clusterName)) {
+ existingClusterNameErrorDecoration.setDescriptionText("Cluster [" + clusterName + "] already exists!");
+ existingClusterNameErrorDecoration.show();
+ okButton.setEnabled(false);
+ } else {
+ existingClusterNameErrorDecoration.hide();
+ }
+
+ if(serverNameText.getText().trim().isEmpty()) {
+ serverNameErrorDecoration.show();
+ okButton.setEnabled(false);
+ } else {
+ serverNameErrorDecoration.hide();
+ }
+ }
+ }
+
+ private void createRadioButtonListeners(final Composite parent) {
+ if (clusters.size() > 0) {
+ selectButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ stackLayout.topControl = clusterSelectionComposite;
+ clusterNameCombo.select(0);
+ validate();
+ parent.layout();
+ clusterNameCombo.setFocus();
+ }
+ });
+ }
+ createButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ stackLayout.topControl = clusterCreationComposite;
+ validate();
+ parent.layout();
+ newClusterNameText.setFocus();
+ }
+ });
+ registerButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ stackLayout.topControl = clusterRegisterComposite;
+ validate();
+ parent.layout();
+ existingClusterNameText.setFocus();
+ }
+ });
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+
+ setupDataBinding();
+ }
+
+ private ControlDecoration createErrorDecoration(Text text, String message) {
+ ControlDecoration errorDecoration = guiHelper.createErrorDecoration(text);
+ errorDecoration.setDescriptionText(message);
+ errorDecoration.hide();
+ return errorDecoration;
+ }
+
+ /**
+ * Sets up data binding between the text fields and the connection details object. Also attaches a "string required"
+ * validator to the "password" text field. This validator is configured to do the following on validation failure<br>
+ * <li>show an ERROR decorator</li><li>disable the "Login" button
+ */
+ private void setupDataBinding() {
+ clusterNameCombo.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if(clusterNameCombo.getText().trim().isEmpty()) {
+ okButton.setEnabled(false);
+ newClusterNameErrorDecoration.show();
+ } else {
+ okButton.setEnabled(true);
+ newClusterNameErrorDecoration.hide();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void okPressed() {
+ if(selectButton != null && selectButton.getSelection()) {
+ clusterMode = CLUSTER_MODE.SELECT;
+ clusterName = clusterNameCombo.getText();
+
+ if(dontAskAgainButton.getSelection()) {
+ preferenceStore.setValue(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, false);
+ preferenceStore.setValue(PreferenceConstants.P_DEFAULT_CLUSTER_NAME, clusterName);
+ } else {
+ preferenceStore.setValue(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, true);
+ }
+ } else if(createButton.getSelection()) {
+ clusterMode = CLUSTER_MODE.CREATE;
+ clusterName = newClusterNameText.getText().trim();
+ } else if(registerButton.getSelection()) {
+ clusterMode = CLUSTER_MODE.REGISTER;
+ clusterName = existingClusterNameText.getText().trim();
+ serverName = serverNameText.getText().trim();
+ }
+ super.okPressed();
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public CLUSTER_MODE getClusterMode() {
+ return clusterMode;
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumePage1.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumePage1.java
new file mode 100644
index 00000000..9f1ec929
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumePage1.java
@@ -0,0 +1,473 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.model.Volume.NAS_PROTOCOL;
+import org.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.utils.ValidationUtil;
+
+
+public class CreateVolumePage1 extends WizardPage {
+ public static final String PAGE_NAME = "create.volume.page.1";
+ private Text txtName;
+ private ComboViewer typeComboViewer;
+ private Text txtAccessControl;
+ private Text txtCifsUsers;
+ private Volume volume = new Volume();
+ private Button btnNfs;
+ private Button btnCIFS;
+ private Button btnStartVolume;
+ private Link linkCustomize;
+ private List<Device> allDevices;
+ private List<Device> selectedDevices;
+
+ /**
+ * Create the wizard.
+ */
+ public CreateVolumePage1() {
+ super(PAGE_NAME);
+ setTitle("Create Volume");
+ setDescription("Create a new Volume by choosing bricks from the cluster servers and configuring the volume properties.");
+
+ // by default, we create volume with all available disks
+ allDevices = GlusterDataModelManager.getInstance().getReadyDevicesOfAllServers();
+ selectedDevices = allDevices; // volume.setDisks(allDisks);
+ }
+
+ /**
+ * Create contents of the wizard.
+ * @param parent
+ */
+ public void createControl(Composite parent) {
+ setPageComplete(false);
+ Composite container = createContainer(parent);
+
+ createEmptyRow(container);
+
+ createNameLabel(container);
+ createNameText(container);
+
+ createTypeLabel(container);
+ createTypeCombo(container);
+
+// createTransportTypeLabel(container);
+// createTransportTypeValueLabel(container);
+
+ createDisksLabel(container);
+ createDisksCustomizeLink(container);
+
+ createNasProtocolLabel(container);
+ createNasProtocolCheckboxes(container);
+
+ createCifsUserLabel(container);
+ createCifsUserText(container);
+
+ createEmptyLabel(container);
+ createCifsUserInfoLabel(container);
+
+ createAccessControlLabel(container);
+ createAccessControlText(container);
+
+ createEmptyLabel(container);
+ createAccessControlInfoLabel(container);
+
+ createStartVolumeLabel(container);
+ createStartVolumeCheckbox(container);
+ }
+
+ private void createStartVolumeCheckbox(Composite container) {
+ btnStartVolume = new Button(container, SWT.CHECK);
+ btnStartVolume.setSelection(true);
+ }
+
+ private void createStartVolumeLabel(Composite container) {
+ Label lblStartVolume = new Label(container, SWT.NONE);
+ lblStartVolume.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblStartVolume.setText("Start Volume: ");
+ }
+
+ private void createCifsUserInfoLabel(Composite container) {
+ Label lblCifsUserInfo = new Label(container, SWT.TOP);
+ lblCifsUserInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
+ lblCifsUserInfo.setText("(Comma separated list user names)");
+ }
+
+ private void createAccessControlInfoLabel(Composite container) {
+ Label lblAccessControlInfo = new Label(container, SWT.TOP);
+ lblAccessControlInfo.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
+ lblAccessControlInfo.setText("(Comma separated list of IP addresses/hostnames)");
+ }
+
+ private void createEmptyLabel(Composite container) {
+ new Label(container, SWT.NONE);
+ }
+
+ private void createAccessControlText(Composite container) {
+ txtAccessControl = new Text(container, SWT.BORDER);
+ txtAccessControl.setText("*");
+ GridData accessControlData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
+ accessControlData.widthHint = 300;
+ txtAccessControl.setLayoutData(accessControlData);
+ txtAccessControl.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateForm();
+ }
+ });
+ }
+
+ private void createAccessControlLabel(Composite container) {
+ Label lblAccessControl = new Label(container, SWT.NONE);
+ lblAccessControl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblAccessControl.setText("Allow Access From: ");
+ }
+
+ private void createCifsUserLabel(Composite container) {
+ Label lblAccessControl = new Label(container, SWT.NONE);
+ lblAccessControl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblAccessControl.setText("CIFS Users: ");
+ }
+
+ private void createCifsUserText(Composite container) {
+ txtCifsUsers = new Text(container, SWT.BORDER);
+// txtCifsUsers.setText("testuser1,testuser2,testuser3");
+ GridData cifsControlData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
+ cifsControlData.widthHint = 300;
+ txtCifsUsers.setLayoutData(cifsControlData);
+ txtCifsUsers.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateForm();
+ }
+ });
+ }
+
+ private void createNasProtocolCheckboxes(Composite container) {
+ Button btnGluster = new Button(container, SWT.CHECK);
+ btnGluster.setEnabled(false);
+ btnGluster.setSelection(true);
+ btnGluster.setText("Gluster");
+ createEmptyLabel(container);
+
+ btnNfs = new Button(container, SWT.CHECK);
+ btnNfs.setEnabled(true);
+ btnNfs.setSelection(true);
+ btnNfs.setText("NFS");
+ createEmptyLabel(container);
+
+ btnCIFS = new Button(container, SWT.CHECK);
+ btnCIFS.setEnabled(true);
+ btnCIFS.setSelection(false);
+ btnCIFS.setText("CIFS");
+ btnCIFS.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ validateForm();
+ }
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ validateForm();
+ }
+ });
+ }
+
+ private void createNasProtocolLabel(Composite container) {
+ Label lblNasProtocol = new Label(container, SWT.RIGHT);
+ lblNasProtocol.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblNasProtocol.setText("Access Protocol: ");
+ }
+
+ private void createDisksCustomizeLink(Composite container) {
+ linkCustomize = new Link(container, SWT.UNDERLINE_LINK);
+ linkCustomize.setText("All Brick(s) (<a>customize</a>)" );
+ linkCustomize.setEnabled(false);
+ linkCustomize.addListener (SWT.Selection, new Listener () {
+ public void handleEvent(Event event) {
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ SelectDisksDialog dialog = new SelectDisksDialog(getShell(), allDevices, selectedDevices, txtName.getText().trim());
+
+ dialog.create();
+ if(dialog.open() == Window.OK) {
+ // user has customized disks. get them from the dialog box.
+ selectedDevices = dialog.getSelectedDevices();
+ linkCustomize.setText("" + selectedDevices.size() + " Brick(s) (<a>customize</a>)");
+ validateForm();
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private void createDisksLabel(Composite container) {
+ Label lblDisks = new Label(container, SWT.RIGHT);
+ lblDisks.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblDisks.setText("Bricks: ");
+ }
+
+ private void createTypeCombo(Composite container) {
+ typeComboViewer = new ComboViewer(container, SWT.READ_ONLY);
+ Combo typeCombo = typeComboViewer.getCombo();
+ GridData typeComboData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
+ typeCombo.setLayoutData(typeComboData);
+ typeComboViewer.setContentProvider(new ArrayContentProvider());
+
+ VOLUME_TYPE[] volumeTypes = new VOLUME_TYPE[3];
+ volumeTypes[0] = VOLUME_TYPE.DISTRIBUTE;
+ volumeTypes[1] = VOLUME_TYPE.REPLICATE;
+ volumeTypes[2] = VOLUME_TYPE.STRIPE;
+
+ typeComboViewer.setInput(volumeTypes);
+ typeCombo.select(0); // default type = Plain Distribute
+ typeComboViewer.setLabelProvider(new LabelProvider() {
+ @Override
+ public String getText(Object element) {
+ return Volume.getVolumeTypeStr((VOLUME_TYPE)element);
+ }
+ });
+ typeComboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ validateForm();
+ }
+ });
+ }
+
+ private void createTypeLabel(Composite container) {
+ Label lblType = new Label(container, SWT.NONE);
+ lblType.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblType.setText("Type: ");
+ }
+
+ private void createNameText(Composite container) {
+ txtName = new Text(container, SWT.BORDER);
+ GridData txtNameData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
+ txtNameData.widthHint = 300;
+ txtName.setTextLimit(32);
+ txtName.setLayoutData(txtNameData);
+ txtName.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateForm();
+ }
+ });
+ }
+
+ private void createNameLabel(Composite container) {
+ Label lblName = new Label(container, SWT.NONE);
+ lblName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ lblName.setText("Name: ");
+ }
+
+ private void createEmptyRow(Composite container) {
+ createEmptyLabel(container);
+ createEmptyLabel(container);
+ }
+
+ private Composite createContainer(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ setControl(container);
+
+ GridLayout gl_container = new GridLayout(2, false);
+ gl_container.verticalSpacing = 10;
+ gl_container.marginHeight = 10;
+ gl_container.marginLeft = 20;
+ gl_container.horizontalSpacing = 10;
+ container.setLayout(gl_container);
+ return container;
+ }
+
+ public Volume getVolume() {
+ volume.setName(txtName.getText());
+
+ IStructuredSelection selection = (IStructuredSelection)typeComboViewer.getSelection();
+ volume.setVolumeType((VOLUME_TYPE)selection.getFirstElement());
+ volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT);
+ volume.setStripeCount(Volume.DEFAULT_STRIPE_COUNT);
+
+ volume.setTransportType(TRANSPORT_TYPE.ETHERNET); // Support only for Ethernet
+ Set<NAS_PROTOCOL> nasProtocols = new HashSet<Volume.NAS_PROTOCOL>();
+ nasProtocols.add(NAS_PROTOCOL.GLUSTERFS);
+ nasProtocols.add(NAS_PROTOCOL.NFS);
+
+ volume.setAccessControlList(txtAccessControl.getText());
+
+ if (btnNfs.getSelection()) {
+ volume.enableNFS();
+ } else {
+ volume.disableNFS();
+ }
+
+ if (btnCIFS.getSelection()) {
+ volume.enableCifs();
+ volume.setCifsUsers(Arrays.asList(txtCifsUsers.getText().split(",")));
+ } else {
+ volume.disableCifs();
+ }
+
+ addVolumeBricks();
+ return volume;
+ }
+
+ private void addVolumeBricks() {
+ // first clear existing bricks, if any
+ volume.getBricks().clear();
+
+ for (Device device : selectedDevices) {
+ Brick brick = new Brick(device.getServerName(), BRICK_STATUS.ONLINE, device.getMountPoint() + "/"
+ + volume.getName());
+ volume.addBrick(brick);
+ }
+ }
+
+ public Boolean startVolumeAfterCreation() {
+ return btnStartVolume.getSelection();
+ }
+
+ public Boolean volumeExists(String volumeName) {
+ List<Volume> volumes = GlusterDataModelManager.getInstance().getModel().getCluster().getVolumes();
+ for (Volume volume : volumes) {
+ if (volume.getName().equals(volumeName)) {
+ setErrorMessage("Volume name already exists.");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void validateForm() {
+ clearErrors();
+ validateVolumeName();
+ validateCifsUsers();
+ validateAccessControl();
+ validateDisks();
+ }
+
+ private void validateDisks() {
+ int diskCount = selectedDevices.size();
+
+ if(diskCount < 1) {
+ setError("At least one brick must be selected!");
+ }
+
+ VOLUME_TYPE volumeType = (VOLUME_TYPE) ((IStructuredSelection) typeComboViewer
+ .getSelection()).getFirstElement();
+ if ((volumeType == VOLUME_TYPE.DISTRIBUTED_REPLICATE || volumeType == VOLUME_TYPE.REPLICATE ) && diskCount % 2 != 0) {
+ setError("Mirror type volume requires bricks in multiples of two");
+ } else if ((volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE || volumeType == VOLUME_TYPE.STRIPE) && diskCount % 4 != 0) {
+ setError("Stripe type volume requires bricks in multiples of four");
+ }
+ }
+
+ private void validateAccessControl() {
+ String accessControl = txtAccessControl.getText().trim();
+ if (accessControl.length() == 0) {
+ setError("Please enter Access Control");
+ return;
+ }
+
+ if (!ValidationUtil.isValidAccessControl(accessControl)) {
+ setError("Invalid IP address/Host name [" + ValidationUtil.getInvalidIpOrHostname(accessControl)
+ + "]. Please enter a valid value!");
+ }
+ }
+
+
+ private void validateCifsUsers() {
+ if (btnCIFS.getSelection()) {
+ String cifsUserList = txtCifsUsers.getText().trim();
+ if (cifsUserList.length() == 0) {
+ setError("Please enter cifs user name");
+ return;
+ }
+ }
+ }
+
+ private void validateVolumeName() {
+ String volumeName = txtName.getText().trim();
+ String volumeNameToken = "^[a-zA-Z][a-zA-Z0-9\\-]*";
+
+ if (volumeName.length() > 0) {
+ linkCustomize.setEnabled(true);
+ }
+
+ if(volumeName.length() == 0) {
+ setError("Please enter Volume Name");
+ linkCustomize.setEnabled(false);
+ }
+
+ if (!volumeName.matches(volumeNameToken)) {
+ setError("Please enter valid Volume Name");
+ }
+
+ if(!volumeExists(volumeName)) {
+ setError("Volume [" + volumeName + "] already exists!");
+ }
+ }
+
+ private void clearErrors() {
+ setErrorMessage(null);
+ setPageComplete(true);
+ }
+
+ private void setError(String errorMsg) {
+ setPageComplete(false);
+ setErrorMessage(errorMsg);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumeWizard.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumeWizard.java
new file mode 100644
index 00000000..6aa81b7f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/CreateVolumeWizard.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+
+
+public class CreateVolumeWizard extends Wizard {
+ private static final String title = "Gluster Management Console - Create Volume";
+ private CreateVolumePage1 page;
+
+ public CreateVolumeWizard() {
+ setWindowTitle(title);
+ setHelpAvailable(false); // TODO: Introduce wizard help
+ }
+
+ @Override
+ public void addPages() {
+ page = new CreateVolumePage1();
+ addPage(page);
+ }
+
+ @Override
+ public boolean performFinish() {
+ Volume newVolume = page.getVolume();
+ VolumesClient volumesClient = new VolumesClient();
+
+ try {
+ List<String> servers = GlusterDataModelManager.getInstance().getOfflineServers();
+ // One or more servers are offline, Show warning if cifs is enabled
+ if (newVolume.isCifsEnable() && servers != null && servers.size() > 0) {
+ Integer userAction = new MessageDialog(getShell(), "Create Volume", GUIHelper.getInstance().getImage(
+ IImageKeys.VOLUME_16x16),
+ "Performing CIFS updates when one or more servers are offline can trigger "
+ + "inconsistent behavior for CIFS accesses in the cluster." + CoreConstants.NEWLINE
+ + "Are you sure you want to continue?", MessageDialog.QUESTION, new String[] { "No",
+ "Yes" }, -1).open();
+ if (userAction != 1) {
+ return false; // To stay on the create dialog
+ }
+ }
+
+ volumesClient.createVolume(newVolume);
+
+ // Set proper volume type before assign to model
+ VOLUME_TYPE volumetype = newVolume.getVolumeType();
+ if (volumetype == VOLUME_TYPE.REPLICATE && newVolume.getBricks().size() > newVolume.getReplicaCount()) {
+ newVolume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_REPLICATE);
+ } else if (volumetype == VOLUME_TYPE.STRIPE && newVolume.getBricks().size() > newVolume.getStripeCount()) {
+ newVolume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_STRIPE);
+ }
+
+ handleSuccess(newVolume, volumesClient);
+ } catch (Exception e) {
+ String errMsg = e.getMessage();
+ // the error could be in to post-volume-create processing. check if this is the case.
+ if (volumesClient.volumeExists(newVolume.getName())) {
+ handlePartSuccess(newVolume, volumesClient, errMsg);
+ } else {
+ MessageDialog.openError(getShell(), title, "Volume creation failed! Error: " + errMsg);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void handleSuccess(Volume newVolume, VolumesClient volumesClient) {
+ String message = "Volume created successfully!";
+ newVolume.setStatus(VOLUME_STATUS.OFFLINE);
+ boolean warning = false;
+ if (page.startVolumeAfterCreation()) {
+ try {
+ volumesClient.startVolume(newVolume.getName(), false);
+ newVolume.setStatus(VOLUME_STATUS.ONLINE);
+ message = "Volume created and started successfully!";
+ } catch(Exception e) {
+ message = "Volume created successfuly, but couldn't be started. Error: " + e.getMessage();
+ warning = true;
+ }
+ }
+
+ // update the model
+ GlusterDataModelManager.getInstance().addVolume(newVolume);
+ if (warning) {
+ MessageDialog.openWarning(getShell(), title, message);
+ } else {
+ MessageDialog.openInformation(getShell(), title, message);
+ }
+ }
+
+ public void handlePartSuccess(Volume newVolume, VolumesClient volumesClient, String errMsg) {
+ // volume exists. error was in post-volume-create
+ newVolume.setStatus(VOLUME_STATUS.OFFLINE);
+ boolean error = false;
+ String message1 = null;
+ if (page.startVolumeAfterCreation()) {
+ if (MessageDialog.openConfirm(getShell(), title, "Volume created, but following error(s) occured: "
+ + errMsg + CoreConstants.NEWLINE + CoreConstants.NEWLINE
+ + "Do you still want to start the volume [" + newVolume.getName() + "]?")) {
+ try {
+ volumesClient.startVolume(newVolume.getName(), false);
+ newVolume.setStatus(VOLUME_STATUS.ONLINE);
+ message1 = "Volume [" + newVolume.getName() + "] started successfully!"; // Only start operation
+ } catch(Exception e1) {
+ message1 = "Volume couldn't be started. Error: " + e1.getMessage();
+ error = true;
+ }
+ }
+
+ if (error) {
+ MessageDialog.openWarning(getShell(), title, message1);
+ } else if (message1.trim().length() > 0) {
+ MessageDialog.openInformation(getShell(), title, message1);
+ }
+ } else { // Start volume is not checked
+ MessageDialog.openWarning(getShell(), title,
+ "Volume created, but following error(s) occured: " + errMsg);
+ }
+
+ // Fetching actual volume info (because of partial success)
+ Volume volume = newVolume;
+ try {
+ volume = volumesClient.getVolume(newVolume.getName());
+ }catch (Exception e) {
+ GlusterLogger.getInstance().error("Fetching volume details failed:" + e.getMessage());
+ }
+ GlusterDataModelManager.getInstance().addVolume(volume);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/GlusterSupportDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/GlusterSupportDialog.java
new file mode 100644
index 00000000..6eb414f5
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/GlusterSupportDialog.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.FormDialog;
+import org.eclipse.ui.forms.IManagedForm;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormText;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+public class GlusterSupportDialog extends FormDialog {
+
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private FormToolkit toolkit;
+ private ScrolledForm form;
+ private Composite parent;
+
+ public GlusterSupportDialog(Shell shell) {
+ super(shell);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+ this.parent = newShell;
+ newShell.setText("Gluster Management Console - Support Information");
+ }
+
+ protected void createFormContent(IManagedForm mform) {
+ form = mform.getForm();
+ toolkit = mform.getToolkit();
+ form.getBody().setLayout(new GridLayout());
+ createSections();
+ }
+
+ private void createSections() {
+ contactGlusterSupportSection();
+ commingSoonSection();
+ form.layout();
+ form.getParent().layout();
+ }
+
+
+ private void contactGlusterSupportSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Contact Gluster Support", null, 1, false);
+
+ FormText formText = toolkit.createFormText(section, false);
+ toolkit.createLabel(section, "Call 1-800-805-5215", SWT.NONE);
+ toolkit.createLabel(section, "or", SWT.NONE);
+ toolkit.createLabel(section, "Email:support@gluster.com", SWT.NONE);
+// String supportInfo = "<form>" +
+// "Call 1-800-805-5215<br />" +
+// "or<br />" +
+// "Email:support@gluster.com" +
+// "</form>";
+// formText.setText(supportInfo, true, true);
+ GridData layoutData = new GridData();
+ layoutData.widthHint = 730;
+ layoutData.grabExcessHorizontalSpace = true;
+ formText.setLayoutData(layoutData);
+ }
+
+ private void commingSoonSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Coming Soon", null, 7, false);
+ FormText formText = toolkit.createFormText(section, true);
+ String commingSoonInfo = "<form>" +
+ "The following features of GlusterFS will soon be supported in upcoming releases of Gluster Management Console " +
+ "<li>Geo-replication</li>" +
+ "<li>Directory Quota</li>" +
+ "<li>Top and Profile</li>" +
+ "<li>POSIX ACLs Support</li><br />" +
+ "More information about these features can be found at<br /> " +
+ "http://www.gluster.com/community/documentation/index.php/Gluster_3.2:_What_is_New_in_this_Release" +
+ "</form>";
+ formText.setText(commingSoonInfo, true, true);
+ GridData layoutData = new GridData();
+ layoutData.widthHint = 700;
+ layoutData.grabExcessHorizontalSpace = true;
+ formText.setLayoutData(layoutData);
+ formText.addHyperlinkListener(new HyperlinkAdapter() {
+ public void linkActivated(HyperlinkEvent e) {
+ System.out.println("Link activated: " + e.getHref());
+ try {
+ PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser()
+ .openURL(new URL((String) e.getHref()));
+ } catch (PartInitException e1) {
+ e1.printStackTrace();
+ } catch (MalformedURLException e1) {
+ e1.printStackTrace();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent) {
+ return null;
+ }
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/InitDiskDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/InitDiskDialog.java
new file mode 100644
index 00000000..4d06fd3a
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/InitDiskDialog.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ *
+ * InitializeDiskTypeSelection.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.gluster.storage.management.console.utils.GUIHelper;
+
+
+public class InitDiskDialog extends Dialog {
+
+ private Combo formatTypeCombo = null;
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Composite initializeDiskTypeComposite;
+ private Composite composite;
+ private String fsType;
+ private String mountPoint;
+ private Text mountPointText;
+ private String deviceName;
+ private List<String> fsTypes;
+ private static final String DEFAULT_MOUNT_POINT = "/export/";
+
+ public InitDiskDialog(Shell parentShell, String deviceName, List<String> fsTypes) {
+ super(parentShell);
+ this.fsTypes = fsTypes;
+ this.deviceName = deviceName;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Gluster Management Console - Select File System Type");
+ addEscapeListener(newShell);
+ }
+
+ private void addEscapeListener(Shell shell) {
+ shell.addTraverseListener(new TraverseListener() {
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ cancelPressed();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ // Makes sure that child composites inherit the same background
+ parent.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ composite = (Composite) super.createDialogArea(parent);
+ configureDialogLayout(composite);
+ createComposite(composite);
+ return composite;
+ }
+
+ private void configureDialogLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.numColumns = 3;
+ layout.marginLeft = 20;
+ layout.marginRight = 20;
+ layout.marginTop = 20;
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 20;
+ }
+
+ private void createComposite(Composite composite) {
+ initializeDiskTypeComposite = new Composite(composite, SWT.NONE);
+ GridLayout layout = new GridLayout(3, false);
+ initializeDiskTypeComposite.setLayout(layout);
+
+ createLabel(initializeDiskTypeComposite, "File system ");
+ createFormatTypeCombo(initializeDiskTypeComposite);
+ createLabel(initializeDiskTypeComposite, "Mount point ");
+ createMountPointText(initializeDiskTypeComposite);
+ createChangeLink(initializeDiskTypeComposite);
+ }
+
+ private void createLabel(Composite composite, String labelText) {
+ Label formatTypeLabel = new Label(composite, SWT.NONE);
+ formatTypeLabel.setText(labelText);
+ formatTypeLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
+ }
+
+ private void createFormatTypeCombo(Composite composite) {
+ formatTypeCombo = new Combo(composite, SWT.READ_ONLY);
+ formatTypeCombo.setItems(fsTypes.toArray(new String[0]));
+ formatTypeCombo.select(0);
+ new Label(composite, SWT.NONE);
+ }
+
+ private void createMountPointText(Composite container) {
+ mountPointText = new Text(container, SWT.BORDER);
+ GridData txtNameData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
+ txtNameData.widthHint = 400;
+ mountPointText.setTextLimit(100);
+ mountPointText.setLayoutData(txtNameData);
+ mountPointText.setText(DEFAULT_MOUNT_POINT + deviceName);
+ mountPointText.setEnabled(false);
+ mountPointText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validateMountPoint();
+ }
+ });
+ }
+
+ private void createChangeLink(Composite container) {
+ final Hyperlink changeLink = new Hyperlink(container, SWT.UNDERLINE_SINGLE);
+ changeLink.setText("change");
+ changeLink.setUnderlined(true);
+ changeLink.setForeground(new Color(Display.getDefault(), 0, 0, 255));
+
+ changeLink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ if (!mountPointText.isEnabled()) {
+ changeLink.setVisible(false);
+ mountPointText.setEnabled(true);
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void okPressed() {
+ fsType = formatTypeCombo.getText().trim();
+ mountPoint = mountPointText.getText().trim();
+ if (validateForm()) {
+ super.okPressed();
+ } else {
+ MessageDialog.openError(getShell(), "Initialize Disk - Error", "Please enter a valid mount point");
+ }
+ }
+
+ @Override
+ public void cancelPressed() {
+ super.cancelPressed();
+ }
+
+ private boolean validateMountPoint() {
+ String mountPoint = mountPointText.getText().trim();
+ if (mountPoint.isEmpty()) {
+ return false;
+ }
+ return mountPoint.matches("^/.+");
+ }
+
+ private boolean validateForm() {
+ return (!formatTypeCombo.getText().trim().isEmpty() && validateMountPoint());
+ }
+
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+ public String getFSType() {
+ return fsType;
+ }
+
+ public String getMountPoint() {
+ return mountPoint;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/LoginDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/LoginDialog.java
new file mode 100644
index 00000000..ccbea44f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/LoginDialog.java
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.beans.PojoProperties;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.client.ClustersClient;
+import org.gluster.storage.management.client.UsersClient;
+import org.gluster.storage.management.console.Activator;
+import org.gluster.storage.management.console.ConsoleConstants;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.dialogs.ClusterSelectionDialog.CLUSTER_MODE;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.validators.StringRequiredValidator;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.ConnectionDetails;
+
+
+/**
+ * Login dialog, which prompts for the user's account info, and has Login and Cancel buttons.
+ */
+public class LoginDialog extends Dialog {
+ public static final int RETURN_CODE_ERROR = 2;
+ private Text userIdText = null;
+ private Text passwordText = null;
+ private Button okButton;
+
+ private final ConnectionDetails connectionDetails = new ConnectionDetails("gluster", "");
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Composite composite;
+
+ public LoginDialog(Shell parentShell) {
+ super(parentShell);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Gluster Management Console");
+ addEscapeListener(newShell);
+ }
+
+ private void addEscapeListener(Shell shell) {
+ shell.addTraverseListener(new TraverseListener() {
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ cancelPressed();
+ }
+ }
+ });
+ }
+
+ private void createUserIdLabel(Composite composite) {
+ Label userIdLabel = new Label(composite, SWT.NONE);
+ userIdLabel.setText("&User ID:");
+ userIdLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private void createUserIdText(Composite composite) {
+ userIdText = new Text(composite, SWT.BORDER);
+ userIdText.setText("gluster");
+ userIdText.setEnabled(false);
+
+ GridData layoutData = new GridData(convertWidthInCharsToPixels(32), 15);
+ userIdText.setLayoutData(layoutData);
+ }
+
+ private void createPasswordLabel(Composite composite) {
+ Label passwordLabel = new Label(composite, SWT.NONE);
+ passwordLabel.setText("&Password:");
+ passwordLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private void createPasswordText(Composite composite) {
+ passwordText = new Text(composite, SWT.BORDER | SWT.PASSWORD);
+
+ GridData layoutData = new GridData(convertWidthInCharsToPixels(32), 15);
+ passwordText.setLayoutData(layoutData);
+ }
+
+ private void configureDialogLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.numColumns = 2;
+ layout.marginLeft = 10;
+ layout.marginRight = 10;
+ layout.marginTop = 30;
+ layout.marginBottom = 0;
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 10;
+ }
+
+ private void configureButtonCompositeLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.marginLeft = 20;
+ layout.marginRight = 20;
+ layout.marginTop = 0;
+ layout.horizontalSpacing = 10;
+ layout.verticalSpacing = 10;
+ }
+
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+
+ getShell().setSize(390, 240);
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ parent.setBackgroundImage(guiHelper.getImage(IImageKeys.DIALOG_SPLASH_IMAGE));
+ // Makes sure that child composites inherit the same background
+ parent.setBackgroundMode(SWT.INHERIT_FORCE);
+
+ composite = (Composite) super.createDialogArea(parent);
+ configureDialogLayout(composite);
+ GridData layoutData = new GridData(390, 110);
+ composite.setLayoutData(layoutData);
+
+ createUserIdLabel(composite);
+ createUserIdText(composite);
+
+ createPasswordLabel(composite);
+ createPasswordText(composite);
+
+ setupAutoLoginIfRequired();
+ return composite;
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ configureButtonCompositeLayout(parent);
+
+ GridData layoutData = new GridData(390, 130);
+ layoutData.horizontalAlignment = SWT.CENTER;
+ layoutData.verticalAlignment = SWT.TOP;
+ layoutData.grabExcessHorizontalSpace = true;
+ parent.setLayoutData(layoutData);
+
+ layoutData = new GridData();
+ layoutData.widthHint = 70;
+ layoutData.horizontalAlignment = SWT.RIGHT;
+ layoutData.grabExcessHorizontalSpace = true;
+
+ Button cancelButton = createButton(parent, IDialogConstants.CANCEL_ID, "&Cancel", false);
+ cancelButton.setLayoutData(layoutData);
+
+ layoutData = new GridData();
+ layoutData.widthHint = 70;
+ layoutData.horizontalAlignment = SWT.LEFT;
+ layoutData.grabExcessHorizontalSpace = true;
+
+ okButton = createButton(parent, IDialogConstants.OK_ID, "&Login", true);
+ okButton.setLayoutData(layoutData);
+
+ setupDataBinding();
+ }
+
+ private void setupAutoLoginIfRequired() {
+ final String password = System.getProperty(ConsoleConstants.PROPERTY_AUTO_LOGIN_PASSWORD, null);
+ if (password == null) {
+ return;
+ }
+ getShell().addShellListener(new ShellAdapter() {
+ @Override
+ public void shellActivated(ShellEvent e) {
+ super.shellActivated(e);
+
+ if (passwordText.getText().isEmpty()) {
+ // Check whether the password has been passed as system parameter. This can be used for avoiding
+ // human intervention on login dialog while running SWTBot automated tests.
+ passwordText.setText(password);
+ okPressed();
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets up data binding between the text fields and the connection details object. Also attaches a "string required"
+ * validator to the "password" text field. This validator is configured to do the following on validation failure<br>
+ * <li>show an ERROR decorator</li><li>disable the "Login" button
+ */
+ private void setupDataBinding() {
+ DataBindingContext dataBindingContext = new DataBindingContext(SWTObservables.getRealm(Display.getCurrent()));
+ UpdateValueStrategy passwordBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+
+ // The Validator shows error decoration and disables OK button on
+ // validation failure
+ passwordBindingStrategy.setBeforeSetValidator(new StringRequiredValidator("Please enter password!", guiHelper
+ .createErrorDecoration(passwordText), okButton));
+
+ dataBindingContext.bindValue(WidgetProperties.text(SWT.Modify).observe(passwordText),
+ PojoProperties.value("password").observe(connectionDetails), passwordBindingStrategy,
+ passwordBindingStrategy);
+
+ UpdateValueStrategy userIdBindingStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+ dataBindingContext
+ .bindValue(WidgetProperties.text(SWT.Modify).observe(userIdText), PojoProperties.value("userId")
+ .observe(connectionDetails), userIdBindingStrategy, userIdBindingStrategy);
+ }
+
+ protected void okPressed() {
+ String user = connectionDetails.getUserId();
+ String password = connectionDetails.getPassword();
+
+ UsersClient usersClient = new UsersClient();
+ try {
+ usersClient.authenticate(user, password);
+ } catch(Exception e) {
+ MessageDialog.openError(getShell(), "Authentication Failed", e.getMessage());
+ setReturnCode(RETURN_CODE_ERROR);
+ return;
+ }
+
+ // authentication successful. close the login dialog and open the next one.
+ close();
+
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ boolean showClusterSelectionDialog = preferenceStore.getBoolean(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG);
+
+ // If the password is default, Let user to change the password
+ if (password.equalsIgnoreCase(CoreConstants.DEFAULT_PASSWORD)) {
+ String oldSecurityTokeString = GlusterDataModelManager.getInstance().getSecurityToken();
+ ChangePasswordDialog dialog = new ChangePasswordDialog(getShell());
+
+ if (dialog.open() == Dialog.CANCEL) {
+ MessageDialog.openError(getShell(), "Change password Cancelled",
+ "Password must be changed on first login!" + CoreConstants.NEWLINE + "Application will close.");
+ cancelPressed();
+ return;
+ }
+
+ // after first login, cluster selection dialog must be shown.
+ showClusterSelectionDialog = true;
+ }
+
+ ClustersClient clustersClient = new ClustersClient();
+
+ CLUSTER_MODE mode;
+ String clusterName = null;
+ if (!showClusterSelectionDialog) {
+ clusterName = preferenceStore.getString(PreferenceConstants.P_DEFAULT_CLUSTER_NAME);
+ if (clusterName == null || clusterName.isEmpty()) {
+ // Cluster name not available in preferences. Hence we must show the cluster selection dialog.
+ showClusterSelectionDialog = true;
+ } else {
+ mode = CLUSTER_MODE.SELECT;
+ }
+ }
+
+ String serverName = null;
+
+ if (showClusterSelectionDialog) {
+ ClusterSelectionDialog clusterDialog = new ClusterSelectionDialog(getParentShell(),
+ clustersClient.getClusterNames());
+ int userAction = clusterDialog.open();
+ if (userAction == Window.CANCEL) {
+ MessageDialog.openError(getShell(), "Login Cancelled",
+ "User cancelled login at cluster selection. Application will close!");
+ cancelPressed();
+ return;
+ }
+ mode = clusterDialog.getClusterMode();
+ clusterName = clusterDialog.getClusterName();
+ serverName = clusterDialog.getServerName();
+ } else {
+ mode = CLUSTER_MODE.SELECT;
+ }
+
+ try {
+ createOrRegisterCluster(clustersClient, clusterName, serverName, mode);
+
+ final String clusterName1 = clusterName;
+ new ProgressMonitorDialog(getShell()).run(true, false, new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ GlusterDataModelManager.getInstance().initializeModel(clusterName1, monitor);
+ }
+ });
+ super.okPressed();
+ } catch (Exception e) {
+ String errMsg;
+ if(e instanceof InvocationTargetException) {
+ errMsg = ((InvocationTargetException) e).getTargetException().getMessage();
+ } else {
+ errMsg = e.getMessage();
+ }
+ setReturnCode(RETURN_CODE_ERROR);
+ MessageDialog.openError(getShell(), "Gluster Management Console", errMsg);
+ }
+ }
+
+ public void createOrRegisterCluster(ClustersClient clustersClient, String clusterName, String serverName,
+ CLUSTER_MODE mode) {
+ switch (mode) {
+ case SELECT:
+ return;
+ case CREATE:
+ clustersClient.createCluster(clusterName);
+ break;
+ case REGISTER:
+ clustersClient.registerCluster(clusterName, serverName);
+ break;
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickPage1.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickPage1.java
new file mode 100644
index 00000000..80265949
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickPage1.java
@@ -0,0 +1,302 @@
+/**
+ * MigrateBrickPage1.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.TableLabelProviderAdapter;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+public class MigrateBrickPage1 extends WizardPage {
+ private static final String PAGE_NAME = "migrate.disk.page.1";
+
+ private enum DISK_TABLE_COLUMN_INDICES {
+ SERVER, BRICK_DIRECTORY, FREE_SPACE, TOTAL_SPACE
+ }
+
+ private static final String[] DISK_TABLE_COLUMN_NAMES = { "Server", "Brick Directory", "Free Space (GB)", "Total Space (GB)" };
+
+ private Volume volume;
+ private Brick fromBrick;
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+
+ private TableViewer tableViewerTo;
+
+ private TableViewer tableViewerFrom;
+
+ private Button autoCompleteCheckbox;
+
+ private ITableLabelProvider getBrickLabelProvider(final String volumeName) {
+ return new TableLabelProviderAdapter() {
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Brick)) {
+ return null;
+ }
+ Brick brick = (Brick) element;
+ GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ Device device = modelManager.getDeviceForBrickDir(brick);
+ // convert MB to GB
+ String freeSpace = (device == null ? "NA" : NumberUtil.formatNumber(device.getFreeSpace() / 1024));
+ String totalSpace = (device == null ? "NA" : NumberUtil.formatNumber(device.getSpace() / 1024));
+ return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? brick.getServerName()
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.BRICK_DIRECTORY.ordinal() ? brick.getBrickDirectory()
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal() ? freeSpace
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal() ? totalSpace
+ : "Invalid");
+ }
+ };
+ }
+
+ private ITableLabelProvider getDiskLabelProvider(final String volumeName) {
+ return new TableLabelProviderAdapter() {
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (!(element instanceof Device)) {
+ return null;
+ }
+ Device device = (Device) element;
+ return (columnIndex == DISK_TABLE_COLUMN_INDICES.SERVER.ordinal() ? device.getServerName()
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.BRICK_DIRECTORY.ordinal() ? device.getMountPoint() + "/" + volumeName
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal() ? NumberUtil.formatNumber(device.getFreeSpace() / 1024 ) /* Coverted to GB */
+ : columnIndex == DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal() ? NumberUtil.formatNumber(device.getSpace() / 1024) : "Invalid");
+ }
+ };
+ }
+
+ private void setupDiskTable(Composite parent, Table table) {
+ table.setHeaderVisible(true);
+ table.setLinesVisible(false);
+
+ TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, DISK_TABLE_COLUMN_NAMES);
+ parent.setLayout(tableColumnLayout);
+
+ setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.SERVER, SWT.CENTER, 100);
+ setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.BRICK_DIRECTORY, SWT.CENTER, 100);
+ setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.FREE_SPACE, SWT.CENTER, 90);
+ setColumnProperties(table, DISK_TABLE_COLUMN_INDICES.TOTAL_SPACE, SWT.CENTER, 90);
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ public void setColumnProperties(Table table, DISK_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ /**
+ * Create the wizard.
+ */
+ public MigrateBrickPage1(Volume volume, Brick brick) {
+ super(PAGE_NAME);
+ this.volume = volume;
+ this.fromBrick = brick;
+ setTitle("Migrate Brick [" + volume.getName() + "]");
+ setPageDescription(fromBrick.getQualifiedName(), null);
+ setPageComplete(false);
+ }
+
+ private void setPageDescription(String source, String target) {
+ if (source == null) {
+ source = "";
+ }
+ if (target == null) {
+ target = "";
+ }
+ setDescription("Migrate data from \"" + source + "\" to \"" + target + "\"");
+ }
+
+ private Object getSelectedItem(TableViewer tableViewer) {
+ TableItem[] selectedItems = tableViewer.getTable().getSelection();
+ Object selectedDevice = null;
+ for (TableItem item : selectedItems) {
+ selectedDevice = item.getData();
+ }
+ return selectedDevice;
+ }
+
+ private void setupPageLayout(Composite container) {
+ final GridLayout layout = new GridLayout(2, false);
+ layout.verticalSpacing = 10;
+ layout.horizontalSpacing = 10;
+ layout.marginTop = 10;
+ layout.marginLeft = 10;
+ layout.marginRight = 10;
+ container.setLayout(layout);
+ }
+
+ private Composite createTableViewerComposite(Composite parent) {
+ Composite tableViewerComposite = new Composite(parent, SWT.NONE);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ return tableViewerComposite;
+ }
+
+ public String getSourceBrickDir() {
+ Brick sourceBrick = (Brick)getSelectedItem(tableViewerFrom);
+ return sourceBrick.getQualifiedName();
+ }
+
+ public String getTargetBrickDir() {
+ Device targetDevice = (Device)getSelectedItem(tableViewerTo);
+ if (targetDevice == null) {
+ return "";
+ }
+ return targetDevice.getQualifiedBrickName(volume.getName());
+ }
+
+ public Boolean getAutoCommitSelection() {
+ return autoCompleteCheckbox.getSelection();
+ }
+
+ /**
+ * Create contents of the wizard.
+ *
+ * @param parent
+ */
+ public void createControl(Composite parent) {
+ Composite container = new Composite(parent, SWT.NULL);
+ setControl(container);
+
+ setupPageLayout(container);
+
+ GridData labelLayoutData = new GridData(SWT.LEFT, SWT.BOTTOM, true, false);
+ labelLayoutData.minimumWidth = 100;
+ labelLayoutData.verticalAlignment = SWT.BOTTOM;
+ //labelLayoutData.verticalIndent = 10;
+
+ Label lblFromDisk = new Label(container, SWT.NONE);
+ lblFromDisk.setText("From Brick:");
+ lblFromDisk.setLayoutData(labelLayoutData);
+ Label lblToDisk = new Label(container, SWT.NONE);
+ lblToDisk.setText("To Brick:");
+ lblToDisk.setLayoutData(labelLayoutData);
+
+ Text txtFilterFrom = guiHelper.createFilterText(container);
+ Text txtFilterTo = guiHelper.createFilterText(container);
+
+ GlusterDataModelManager glusterDataModelManager = GlusterDataModelManager.getInstance();
+ List<Brick> fromBricks = volume.getBricks();
+ List<Device> toDevices = glusterDataModelManager.getReadyDevicesOfAllServersExcluding(glusterDataModelManager
+ .getDevicesOfVolume(volume));
+
+ tableViewerFrom = createTableViewer(container, getBrickLabelProvider(volume.getName()), fromBricks,
+ txtFilterFrom);
+
+ if(fromBrick != null) {
+ setFromDisk(tableViewerFrom, fromBrick);
+ }
+ tableViewerTo = createTableViewer(container, getDiskLabelProvider(volume.getName()), toDevices, txtFilterTo);
+ tableViewerTo.setSelection(new StructuredSelection(fromBrick));
+
+ // Auto commit selection field
+ Composite autoCommitContainer = new Composite(container, SWT.NONE);
+ GridData data = new GridData();
+ data.horizontalSpan = 2;
+ autoCommitContainer.setLayoutData(data);
+ autoCompleteCheckbox = new Button(autoCommitContainer, SWT.CHECK);
+ autoCompleteCheckbox.setSelection(true);
+ Label lblAutoComplete = new Label(autoCommitContainer, SWT.NONE);
+ lblAutoComplete.setText("Auto commit on migration complete");
+ autoCommitContainer.setLayout( container.getLayout());
+ }
+
+ private void setFromDisk(TableViewer tableViewer, Brick brickToSelect) {
+ Table table = tableViewer.getTable();
+ for (int i = 0; i < table.getItemCount(); i++) {
+ TableItem item = table.getItem(i);
+ if (item.getData() == brickToSelect) {
+ table.select(i);
+ return;
+ }
+ }
+ }
+
+ private void refreshButtonStatus() {
+ if(tableViewerFrom.getSelection().isEmpty() || tableViewerTo.getSelection().isEmpty()) {
+ setPageComplete(false);
+ } else {
+ setPageComplete(true);
+ }
+ }
+
+ private <T> TableViewer createTableViewer(Composite container, ITableLabelProvider diskLabelProvider,
+ List<T> bricks, Text txtFilterText) {
+ Composite tableViewerComposite = createTableViewerComposite(container);
+
+ TableViewer tableViewer = new TableViewer(tableViewerComposite, SWT.SINGLE);
+ tableViewer.setContentProvider(new ArrayContentProvider());
+ tableViewer.setLabelProvider(diskLabelProvider);
+
+ setupDiskTable(tableViewerComposite, tableViewer.getTable());
+ guiHelper.createFilter(tableViewer, txtFilterText, false);
+
+ tableViewer.setInput(bricks.toArray());
+
+ tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ refreshButtonStatus();
+ setPageDescription(getSourceBrickDir(), getTargetBrickDir());
+ }
+ });
+ return tableViewer;
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickWizard.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickWizard.java
new file mode 100644
index 00000000..f5cc0249
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/MigrateBrickWizard.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.net.URI;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class MigrateBrickWizard extends Wizard {
+ private Volume volume;
+ private Brick brick;
+ private MigrateBrickPage1 page;
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private Cluster cluster = modelManager.getModel().getCluster();
+
+ public MigrateBrickWizard(Volume volume, Brick brick) {
+ setWindowTitle("Gluster Management Console - Migrate Brick [" + volume.getName() + "]");
+ this.volume = volume;
+ this.brick = brick;
+ setHelpAvailable(false); // TODO: Introduce wizard help
+ }
+
+ @Override
+ public void addPages() {
+ page = new MigrateBrickPage1(volume, brick);
+ addPage(page);
+ }
+
+ @Override
+ public boolean performFinish() {
+
+ String sourceDir = page.getSourceBrickDir();
+ String targetDir = page.getTargetBrickDir();
+ Boolean autoCommit = page.getAutoCommitSelection();
+ VolumesClient volumesClient = new VolumesClient();
+ String dialogTitle = "Brick migration";
+
+ try {
+ String reference = volume.getName() + "-" + sourceDir + "-" + targetDir;
+ TaskInfo existingTaskInfo = GlusterDataModelManager.getInstance().getTaskByReference(reference);
+ if (existingTaskInfo != null && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS
+ && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_FAILURE) {
+ MessageDialog.openInformation(getShell(), dialogTitle, "Volume brick [" + reference
+ + "] migration is already in progress! Try later.");
+ return true;
+ }
+
+ URI uri = volumesClient.startMigration(volume.getName(), sourceDir, targetDir, autoCommit);
+
+ // To get the object
+ TasksClient taskClient = new TasksClient();
+ TaskInfo taskInfo = taskClient.getTaskInfo(uri);
+ if (taskInfo != null) {
+ // cluster.addTaskInfo(taskInfo);
+ String volumeName = taskInfo.getReference().split("#")[0];
+ modelManager.addTask(taskInfo);
+ modelManager.refreshVolumeData(cluster.getVolume(volumeName));
+
+ // If auto commit selected and migration operation complete immediately,
+ if (taskInfo.getStatus().getCode() == TaskStatus.STATUS_CODE_SUCCESS) {
+ Volume oldVolume = cluster.getVolume(volumeName);
+ Volume newVolume = (new VolumesClient()).getVolume(volumeName);
+
+ modelManager.volumeChanged(oldVolume, newVolume);
+
+ MessageDialog.openInformation(getShell(), dialogTitle, "Brick migration completed successfully");
+ return true;
+ }
+ }
+ MessageDialog.openInformation(getShell(), dialogTitle, "Brick migration started successfully");
+ GUIHelper.getInstance().showTaskView();
+
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), dialogTitle, "Brick Migration failed! [" + e.getMessage() + "]");
+ }
+ return true;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/SelectDisksDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/SelectDisksDialog.java
new file mode 100644
index 00000000..cc6eb83b
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/SelectDisksDialog.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Device;
+
+
+public class SelectDisksDialog extends Dialog {
+
+ private BricksSelectionPage disksPage;
+ private List<Device> allDevices;
+ private List<Device> selectedDevices;
+ private String volumeName;
+
+ /**
+ * Create the dialog.
+ *
+ * @param parentShell
+ */
+ public SelectDisksDialog(Shell parentShell, List<Device> allDevices, List<Device> selectedDevices, String volumeName) {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ this.allDevices = allDevices;
+ this.selectedDevices = selectedDevices;
+ this.volumeName = volumeName;
+ }
+
+ /**
+ * Create contents of the dialog.
+ *
+ * @param parent
+ */
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite container = new Composite(parent, SWT.NONE);
+ GridLayout containerLayout = new GridLayout(2, false);
+ container.setLayout(containerLayout);
+ GridData containerLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ container.setLayoutData(containerLayoutData);
+
+ getShell().setText("Create Volume - Select Bricks");
+
+ disksPage = new BricksSelectionPage(container, SWT.NONE, allDevices, selectedDevices, volumeName);
+ return container;
+ }
+
+ /**
+ * Create contents of the button bar.
+ *
+ * @param parent
+ */
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+ }
+
+ /**
+ * Return the initial size of the dialog.
+ */
+ @Override
+ protected Point getInitialSize() {
+ return new Point(1024, 600);
+ }
+
+
+ @Override
+ protected void okPressed() {
+ if (this.getSelectedDevices().size() == 0) {
+ MessageDialog.openError(getShell(), "Select Brick(s)", "Please select atlease one brick");
+ } else {
+ super.okPressed();
+ }
+ }
+
+ public List<Device> getSelectedDevices() {
+ return disksPage.getChosenDevices();
+ }
+
+ public Set<Brick> getSelectedBricks(String volumeName) {
+ return disksPage.getChosenBricks(volumeName);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ServerAdditionDialog.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ServerAdditionDialog.java
new file mode 100644
index 00000000..99d056e6
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/dialogs/ServerAdditionDialog.java
@@ -0,0 +1,197 @@
+/**
+ * ServerAdditionDialog.java
+ *
+ * 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 org.gluster.storage.management.console.dialogs;
+
+import java.net.URI;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class ServerAdditionDialog extends Dialog {
+ public static final int RETURN_CODE_ERROR = 2;
+ private Text serverName;
+ private Button addButton;
+
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private ControlDecoration errDecoration;
+
+ private Composite composite;
+
+ public ServerAdditionDialog(Shell shell) {
+ super(shell);
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Gluster Management Console - Add Server");
+ addEscapeListener(newShell);
+ }
+
+ private void addEscapeListener(Shell shell) {
+ shell.addTraverseListener(new TraverseListener() {
+
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.ESC) {
+ cancelPressed();
+ }
+ }
+ });
+ }
+
+ /**
+ * Overriding to make sure that the dialog is centered in screen
+ */
+ @Override
+ protected void initializeBounds() {
+ super.initializeBounds();
+
+ guiHelper.centerShellInScreen(getShell());
+ }
+
+ private void configureDialogLayout(Composite composite) {
+ GridLayout layout = (GridLayout) composite.getLayout();
+ layout.numColumns = 2;
+ layout.marginLeft = 20;
+ layout.marginRight = 20;
+ layout.marginTop = 20;
+ layout.horizontalSpacing = 20;
+ layout.verticalSpacing = 20;
+ }
+
+ // ------------------------------------------
+
+ private void createLabel(Composite composite, String label) {
+ Label passwordLabel = new Label(composite, SWT.NONE);
+ passwordLabel.setText(label);
+ passwordLabel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ }
+
+ private Text createServerNameText(Composite composite) {
+ Text field = new Text(composite, SWT.BORDER );
+ GridData layoutData = new GridData(SWT.FILL, GridData.FILL, true, false);
+ layoutData.widthHint = convertWidthInCharsToPixels(32);
+ field.setLayoutData(layoutData);
+ return field;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ composite = (Composite) super.createDialogArea(parent);
+ configureDialogLayout(composite);
+
+ createLabel(composite, "Server Name:");
+ serverName = createServerNameText(composite);
+ errDecoration = guiHelper.createErrorDecoration(serverName);
+
+ createListeners();
+
+ return composite;
+ }
+
+ private void createListeners() {
+ ModifyListener listener = new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ updateButtonStatus();
+ }
+ };
+
+ serverName.addModifyListener(listener);
+ }
+
+ private void updateButtonStatus() {
+ addButton.setEnabled(true);
+ errDecoration.hide();
+
+ if(!serverExists(serverName.getText())) {
+ addButton.setEnabled(false);
+ errDecoration.setDescriptionText("Server name already exists.");
+ errDecoration.show();
+ }
+
+ if(serverName.getText().isEmpty()) {
+ addButton.setEnabled(false);
+ errDecoration.setDescriptionText("Please enter server name!");
+ errDecoration.show();
+ }
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ addButton = createButton(parent, IDialogConstants.OK_ID, "&Add Server", true);
+ addButton.setEnabled(false);
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+ }
+
+ public Boolean serverExists(String serverName) {
+ List<GlusterServer> servers = GlusterDataModelManager.getInstance().getModel().getCluster().getServers();
+ for (GlusterServer server : servers) {
+ if (server.getName().equalsIgnoreCase(serverName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected void okPressed() {
+ GlusterServersClient serversClient = new GlusterServersClient();
+ GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ try {
+ String serverNameText = serverName.getText();
+ URI newServerURI = serversClient.addServer(serverNameText);
+
+ modelManager.addGlusterServer(serversClient.getGlusterServer(newServerURI));
+
+ MessageDialog
+ .openInformation(getShell(), "Add Server", "Server " + serverNameText + " added successfully!");
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), "Server addition Failed", e.getMessage());
+ setReturnCode(RETURN_CODE_ERROR);
+ }
+ this.close();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/jobs/DataSyncJob.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/jobs/DataSyncJob.java
new file mode 100644
index 00000000..ee4daafe
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/jobs/DataSyncJob.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.jobs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.widgets.Display;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.model.GlusterDataModel;
+
+
+/**
+ *
+ */
+public class DataSyncJob extends Job {
+ private static final GlusterLogger logger = GlusterLogger.getInstance();
+
+ public DataSyncJob(String name) {
+ super(name);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+ final GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ // fetch the latest model
+ final GlusterDataModel model = modelManager.fetchModel(monitor);
+ if(model == null) {
+ return Status.CANCEL_STATUS;
+ }
+
+ monitor.beginTask("Notify views", 1);
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ modelManager.updateModel(model);
+ }
+ });
+ monitor.worked(1);
+ monitor.done();
+
+ return Status.OK_STATUS;
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/AlertsPreferencePage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/AlertsPreferencePage.java
new file mode 100644
index 00000000..7855f289
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/AlertsPreferencePage.java
@@ -0,0 +1,38 @@
+package org.gluster.storage.management.console.preferences;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.gluster.storage.management.console.Activator;
+
+
+public class AlertsPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ public AlertsPreferencePage() {
+ super(GRID);
+ setPreferenceStore(Activator.getDefault().getPreferenceStore());
+ setDescription("Gluster Management Console - Alerts");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
+ */
+ @Override
+ protected void createFieldEditors() {
+ addField(new IntegerFieldEditor(PreferenceConstants.P_SERVER_CPU_CRITICAL_THRESHOLD,
+ "&Server CPU usage threshold:", getFieldEditorParent()));
+
+ addField(new IntegerFieldEditor(PreferenceConstants.P_SERVER_MEMORY_USAGE_THRESHOLD,
+ "&Server memory usage threshold (%):", getFieldEditorParent()));
+
+ addField(new IntegerFieldEditor(PreferenceConstants.P_DISK_SPACE_USAGE_THRESHOLD,
+ "&Disk space usage threshold (%):", getFieldEditorParent()));
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/ChartsPreferencePage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/ChartsPreferencePage.java
new file mode 100644
index 00000000..6c4f9506
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/ChartsPreferencePage.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.preferences;
+
+import org.eclipse.jface.preference.ComboFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.gluster.storage.management.console.Activator;
+
+
+/**
+ *
+ */
+public class ChartsPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ public ChartsPreferencePage() {
+ super(GRID);
+ setPreferenceStore(Activator.getDefault().getPreferenceStore());
+ setDescription("Gluster Management Console");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ @Override
+ public void init(IWorkbench workbench) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
+ */
+ @Override
+ protected void createFieldEditors() {
+ String[][] entryNamesAndValues = new String[][] {
+ { "1 day", "1d" }, { "1 week", "1w" }, { "1 month", "1m" }, { "1 year", "1y" } };
+ addField(new ComboFieldEditor(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD, "Aggregated CPU Usage chart period", entryNamesAndValues,
+ getFieldEditorParent()));
+ addField(new ComboFieldEditor(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD, "Aggregated Network Usage chart period", entryNamesAndValues,
+ getFieldEditorParent()));
+ addField(new ComboFieldEditor(PreferenceConstants.P_CPU_CHART_PERIOD, "CPU Usage chart period", entryNamesAndValues,
+ getFieldEditorParent()));
+ addField(new ComboFieldEditor(PreferenceConstants.P_MEM_CHART_PERIOD, "Memory Usage chart period", entryNamesAndValues,
+ getFieldEditorParent()));
+ addField(new ComboFieldEditor(PreferenceConstants.P_NETWORK_CHART_PERIOD, "Network Usage chart period", entryNamesAndValues,
+ getFieldEditorParent()));
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/GlusterPreferencePage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/GlusterPreferencePage.java
new file mode 100644
index 00000000..44ff55ed
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/GlusterPreferencePage.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.preferences;
+
+import java.util.List;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.ComboFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.gluster.storage.management.client.ClustersClient;
+import org.gluster.storage.management.console.Activator;
+
+
+/**
+ * This class represents a preference page that
+ * is contributed to the Preferences dialog. By
+ * subclassing <samp>FieldEditorPreferencePage</samp>, we
+ * can use the field support built into JFace that allows
+ * us to create a page that is small and knows how to
+ * save, restore and apply itself.
+ * <p>
+ * This page is used to modify preferences only. They
+ * are stored in the preference store that belongs to
+ * the main plug-in class. That way, preferences can
+ * be accessed directly via the preference store.
+ */
+public class GlusterPreferencePage
+ extends FieldEditorPreferencePage
+ implements IWorkbenchPreferencePage {
+
+ private List<String> clusterNames;
+
+ public GlusterPreferencePage() {
+ super(GRID);
+ setPreferenceStore(Activator.getDefault().getPreferenceStore());
+ setDescription("Gluster Management Console");
+ }
+
+ /**
+ * Creates the field editors. Field editors are abstractions of
+ * the common GUI blocks needed to manipulate various types
+ * of preferences. Each field editor knows how to save and
+ * restore itself.
+ */
+ public void createFieldEditors() {
+ addField(
+ new BooleanFieldEditor(
+ PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG,
+ "&Show Cluster Selection Dialog on Login:",
+ getFieldEditorParent()));
+
+ String[][] clusterNamesArr = new String[clusterNames.size()][2];
+ for(int i = 0; i < clusterNames.size(); i++) {
+ String clusterName = clusterNames.get(i);
+ clusterNamesArr[i][0] = clusterName;
+ clusterNamesArr[i][1] = clusterName;
+ }
+
+ addField(new ComboFieldEditor(PreferenceConstants.P_DEFAULT_CLUSTER_NAME, "Default &Cluster to manage:",
+ clusterNamesArr, getFieldEditorParent()));
+ addField(new IntegerFieldEditor(PreferenceConstants.P_DATA_SYNC_INTERVAL, "&Refresh Interval (sec):",
+ getFieldEditorParent()));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ public void init(IWorkbench workbench) {
+ clusterNames = new ClustersClient().getClusterNames();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceConstants.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceConstants.java
new file mode 100644
index 00000000..1422a77d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceConstants.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public class PreferenceConstants {
+
+ public static final String P_SHOW_CLUSTER_SELECTION_DIALOG = "show.cluster.selection.dialog";
+ public static final String P_DEFAULT_CLUSTER_NAME = "default.cluster.name";
+ public static final String P_DATA_SYNC_INTERVAL = "data.sync.interval";
+
+ public static final String P_SERVER_CPU_CRITICAL_THRESHOLD = "server.cpu.threshold";
+ public static final String P_SERVER_MEMORY_USAGE_THRESHOLD = "server.memory.threshold";
+ public static final String P_DISK_SPACE_USAGE_THRESHOLD = "disk.space.threshold"; // in percentage
+
+ public static final String P_CPU_CHART_PERIOD = "cpu.chart.period";
+ public static final String P_MEM_CHART_PERIOD = "memory.chart.period";
+ public static final String P_NETWORK_CHART_PERIOD = "network.chart.period";
+ public static final String P_DEFAULT_NETWORK_INTERFACE_PFX = "default.network.interface.";
+ public static final String P_CPU_AGGREGATED_CHART_PERIOD = "cpu.aggregated.chart.period";
+ public static final String P_NETWORK_AGGREGATED_CHART_PERIOD = "network.aggregated.chart.period";
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceInitializer.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceInitializer.java
new file mode 100644
index 00000000..36d8b652
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/preferences/PreferenceInitializer.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.gluster.storage.management.console.Activator;
+
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = Activator.getDefault().getPreferenceStore();
+
+ store.setDefault(PreferenceConstants.P_SHOW_CLUSTER_SELECTION_DIALOG, true);
+
+ // default data sync interval = 5 minutes
+ store.setDefault(PreferenceConstants.P_DATA_SYNC_INTERVAL, 300);
+
+ // Default CPU utilisation threshold
+ store.setDefault(PreferenceConstants.P_SERVER_CPU_CRITICAL_THRESHOLD, 80);
+
+ // Default Memory threshold
+ store.setDefault(PreferenceConstants.P_SERVER_MEMORY_USAGE_THRESHOLD, 80);
+
+ // Default disk free space threshold
+ store.setDefault(PreferenceConstants.P_DISK_SPACE_USAGE_THRESHOLD, 80);
+
+ // Default period for server statistics charts
+ store.setDefault(PreferenceConstants.P_CPU_CHART_PERIOD, "1d");
+ store.setDefault(PreferenceConstants.P_MEM_CHART_PERIOD, "1d");
+ store.setDefault(PreferenceConstants.P_NETWORK_CHART_PERIOD, "1d");
+ store.setDefault(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD, "1d");
+ store.setDefault(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD, "1d");
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/GlusterToolbarManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/GlusterToolbarManager.java
new file mode 100644
index 00000000..fc8ef865
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/GlusterToolbarManager.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.toolbar;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.gluster.storage.management.console.actions.ActionConstants;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class GlusterToolbarManager implements ToolbarManager {
+ private enum ENTITY_TYPE {
+ CLUSTER, VOLUMES, VOLUME, GLUSTER_SERVERS, GLUSTER_SERVER, DISCOVERED_SERVERS, DISCOVERED_SERVER, TASK
+ };
+
+ private IWorkbenchWindow window;
+ private final Map<Class<? extends Entity>, ENTITY_TYPE> entityTypeMap = createEntityTypeMap();
+ private final Map<ENTITY_TYPE, String> actionSetMap = createActionSetMap();
+
+ private Map<Class<? extends Entity>, ENTITY_TYPE> createEntityTypeMap() {
+ Map<Class<? extends Entity>, ENTITY_TYPE> entityTypeMap = new HashMap<Class<? extends Entity>, GlusterToolbarManager.ENTITY_TYPE>();
+ entityTypeMap.put(Cluster.class, ENTITY_TYPE.CLUSTER);
+ entityTypeMap.put(Volume.class, ENTITY_TYPE.VOLUME);
+ entityTypeMap.put(Server.class, ENTITY_TYPE.DISCOVERED_SERVER);
+ entityTypeMap.put(GlusterServer.class, ENTITY_TYPE.GLUSTER_SERVER);
+ entityTypeMap.put(TaskInfo.class, ENTITY_TYPE.TASK);
+
+ return entityTypeMap;
+ }
+
+ private Map<ENTITY_TYPE, String> createActionSetMap() {
+ Map<ENTITY_TYPE, String> actionSetMap = new HashMap<GlusterToolbarManager.ENTITY_TYPE, String>();
+ actionSetMap.put(ENTITY_TYPE.CLUSTER, ActionConstants.ACTION_SET_CLUSTER);
+ actionSetMap.put(ENTITY_TYPE.VOLUMES, ActionConstants.ACTION_SET_VOLUMES);
+ actionSetMap.put(ENTITY_TYPE.VOLUME, ActionConstants.ACTION_SET_VOLUME);
+ actionSetMap.put(ENTITY_TYPE.GLUSTER_SERVERS, ActionConstants.ACTION_SET_GLUSTER_SERVERS);
+ actionSetMap.put(ENTITY_TYPE.GLUSTER_SERVER, ActionConstants.ACTION_SET_GLUSTER_SERVER);
+ actionSetMap.put(ENTITY_TYPE.DISCOVERED_SERVERS, ActionConstants.ACTION_SET_DISCOVERED_SERVERS);
+ actionSetMap.put(ENTITY_TYPE.DISCOVERED_SERVER, ActionConstants.ACTION_SET_DISCOVERED_SERVER);
+ actionSetMap.put(ENTITY_TYPE.TASK, ActionConstants.ACTION_SET_TASK);
+
+ return actionSetMap;
+ }
+
+ public GlusterToolbarManager(IWorkbenchWindow window) {
+ this.window = window;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private ENTITY_TYPE getEntityType(Entity entity) {
+ if (entity instanceof EntityGroup) {
+ EntityGroup entityGroup = (EntityGroup) entity;
+ if (entityGroup.getEntityType() == Volume.class) {
+ return ENTITY_TYPE.VOLUMES;
+ } else if (entityGroup.getEntityType() == GlusterServer.class) {
+ return ENTITY_TYPE.GLUSTER_SERVERS;
+ } else {
+ return ENTITY_TYPE.DISCOVERED_SERVERS;
+ }
+ }
+
+ return entityTypeMap.get(entity.getClass());
+ }
+
+ @Override
+ public void updateToolbar(Entity entity) {
+ ENTITY_TYPE entityType = getEntityType(entity);
+ IWorkbenchPage page = window.getActivePage();
+
+ for (ENTITY_TYPE targetEntityType : actionSetMap.keySet()) {
+ String actionSetId = actionSetMap.get(targetEntityType);
+ if (entityType == targetEntityType) {
+ // show only the action set mapped to given entity
+ page.showActionSet(actionSetId);
+ } else {
+ page.hideActionSet(actionSetId);
+ }
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/ToolbarManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/ToolbarManager.java
new file mode 100644
index 00000000..e4b8d320
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/toolbar/ToolbarManager.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.toolbar;
+
+import org.gluster.storage.management.core.model.Entity;
+
+/**
+ * Whenever the current selection/action demands changes to the toolbar, the toolbar manager is used to update the
+ * toolbar.
+ */
+public interface ToolbarManager {
+ /**
+ * Updates the toolbar for given entity. This typically means that user is working with the given entity, and hence
+ * the toolbar actions related to that entity should be made visible, and other un-related actions should be hidden.
+ *
+ * @param entity
+ */
+ public void updateToolbar(Entity entity);
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartUtil.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartUtil.java
new file mode 100644
index 00000000..b5d2a602
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartUtil.java
@@ -0,0 +1,339 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.birt.chart.util.CDateTime;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.gluster.storage.management.console.Activator;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.NetworkInterface;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.ServerStatsRow;
+
+import com.ibm.icu.util.Calendar;
+
+/**
+ *
+ */
+public class ChartUtil {
+ private static final ChartUtil instance = new ChartUtil();
+ private static final int CHART_WIDTH = 350;
+ private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+
+ private ChartUtil() {
+ }
+
+ public static ChartUtil getInstance() {
+ return instance;
+ }
+
+ /**
+ * @param toolkit
+ * @param section
+ * @param stats
+ * @param dataColumnIndex
+ * @param unit
+ * @param timestampFormat
+ * @param listener
+ * @param maxValue
+ * @return The composite containing the various links related to the created chart
+ */
+ public Composite createAreaChart(FormToolkit toolkit, Composite section, ServerStats stats, int dataColumnIndex,
+ String unit, String timestampFormat, ChartPeriodLinkListener listener, double maxValue, int linkColumnCount) {
+ if (stats == null) {
+ toolkit.createLabel(section, "Server statistics not available. Try after some time!");
+ return null;
+ }
+
+ List<Calendar> timestamps = new ArrayList<Calendar>();
+ List<Double> data = new ArrayList<Double>();
+
+ extractChartData(stats, timestamps, data, dataColumnIndex);
+
+ if (timestamps.size() == 0) {
+ toolkit.createLabel(section, "Server statistics not available!" + CoreConstants.NEWLINE
+ + "Check if all services are running properly " + CoreConstants.NEWLINE
+ + "on the cluster servers, or try after some time!");
+ return null;
+ }
+
+ createAreaChart(section, timestamps.toArray(new Calendar[0]), data.toArray(new Double[0]), unit,
+ timestampFormat, maxValue);
+
+ // 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) };
+ //
+ // 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, "%");
+ Composite chartLinksComposite = createChartLinks(toolkit, section, linkColumnCount, listener);
+
+ if (linkColumnCount == 5) {
+ createNetworkInterfaceCombo(section, chartLinksComposite, toolkit,
+ (NetworkChartPeriodLinkListener) listener);
+ }
+ return chartLinksComposite;
+ }
+
+ private ChartViewerComposite createAreaChart(Composite section, Calendar timestamps[], Double values[],
+ String unit, String timestampFormat, double maxValue) {
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values,
+ unit, timestampFormat, maxValue);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = CHART_WIDTH;
+ data.heightHint = 250;
+ data.verticalAlignment = SWT.CENTER;
+ chartViewerComposite.setLayoutData(data);
+ return chartViewerComposite;
+ }
+
+ private void extractChartData(ServerStats stats, List<Calendar> timestamps, List<Double> data, int dataColumnIndex) {
+ for (ServerStatsRow row : stats.getRows()) {
+ Double cpuUsage = row.getUsageData().get(dataColumnIndex);
+ if (!cpuUsage.isNaN()) {
+ timestamps.add(new CDateTime(row.getTimestamp() * 1000));
+ data.add(cpuUsage);
+ }
+ }
+ }
+
+ private Composite createChartLinks(FormToolkit toolkit, Composite section, int columnCount,
+ ChartPeriodLinkListener listener) {
+ GridLayout layout = new org.eclipse.swt.layout.GridLayout(columnCount, false);
+ layout.marginBottom = 0;
+ layout.marginTop = 0;
+ layout.marginLeft = (CHART_WIDTH - (50 * columnCount)) / 2;
+ Composite graphComposite = toolkit.createComposite(section, SWT.NONE);
+ graphComposite.setLayout(layout);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = CHART_WIDTH;
+ graphComposite.setLayoutData(data);
+
+ createStatsLink(toolkit, listener, graphComposite, "1 day", GlusterConstants.STATS_PERIOD_1DAY);
+ createStatsLink(toolkit, listener, graphComposite, "1 week", GlusterConstants.STATS_PERIOD_1WEEK);
+ createStatsLink(toolkit, listener, graphComposite, "1 month", GlusterConstants.STATS_PERIOD_1MONTH);
+ createStatsLink(toolkit, listener, graphComposite, "1 year", GlusterConstants.STATS_PERIOD_1YEAR);
+
+ return graphComposite;
+ }
+
+ private void createStatsLink(FormToolkit toolkit, ChartPeriodLinkListener listener, Composite parent, String label,
+ String statsPeriod) {
+ Hyperlink link1 = toolkit.createHyperlink(parent, label, SWT.NONE);
+ link1.addHyperlinkListener(listener.getInstance(statsPeriod));
+ if (listener.getStatsPeriod().equals(statsPeriod)) {
+ link1.setEnabled(false);
+ }
+ }
+
+ public abstract class ChartPeriodLinkListener extends HyperlinkAdapter {
+ protected String statsPeriod;
+ protected String unit;
+ protected int columnCount;
+ protected double maxValue;
+ protected FormToolkit toolkit;
+ protected String serverName;
+ protected int dataColumnIndex;
+
+ public String getStatsPeriod() {
+ return this.statsPeriod;
+ }
+
+ public ChartPeriodLinkListener(String serverName, String statsPeriod, String unit, double maxValue,
+ int columnCount, int dataColumnIndex, FormToolkit toolkit) {
+ this.serverName = serverName;
+ this.statsPeriod = statsPeriod;
+ this.unit = unit;
+ this.columnCount = columnCount;
+ this.maxValue = maxValue;
+ this.dataColumnIndex = dataColumnIndex;
+ this.toolkit = toolkit;
+ }
+
+ public ChartPeriodLinkListener(String serverName, String statsPeriod, FormToolkit toolkit) {
+ this.statsPeriod = statsPeriod;
+ this.serverName = serverName;
+ this.toolkit = toolkit;
+ }
+
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ super.linkActivated(e);
+ Composite section = ((Hyperlink) e.getSource()).getParent().getParent();
+ updatePreference(serverName);
+ }
+
+ public abstract ChartPeriodLinkListener getInstance(String statsPeriod);
+
+ protected abstract void updatePreference(String serverName);
+ }
+
+ public class CpuChartPeriodLinkListener extends ChartPeriodLinkListener {
+ public CpuChartPeriodLinkListener(String serverName, String statsPeriod, FormToolkit toolkit) {
+ super(serverName, statsPeriod, toolkit);
+ }
+
+ private CpuChartPeriodLinkListener(String serverName, String statsPeriod, String unit, double maxValue,
+ int columnCount, int dataColumnIndex, FormToolkit toolkit) {
+ super(serverName, statsPeriod, unit, maxValue, columnCount, dataColumnIndex, toolkit);
+ }
+
+ @Override
+ protected void updatePreference(String serverName) {
+ ServerStats stats;
+ if (serverName == null) {
+ preferenceStore.setValue(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD, statsPeriod);
+ } else {
+ preferenceStore.setValue(PreferenceConstants.P_CPU_CHART_PERIOD, statsPeriod);
+ }
+ }
+
+ @Override
+ public ChartPeriodLinkListener getInstance(String statsPeriod) {
+ return new CpuChartPeriodLinkListener(serverName, statsPeriod, "%", 100, 4, dataColumnIndex, toolkit);
+ }
+ }
+
+ public class MemoryChartPeriodLinkListener extends ChartPeriodLinkListener {
+ public MemoryChartPeriodLinkListener(String serverName, String statsPeriod, FormToolkit toolkit) {
+ super(serverName, statsPeriod, toolkit);
+ }
+
+ private MemoryChartPeriodLinkListener(String serverName, String statsPeriod, String unit, double maxValue,
+ int columnCount, int dataColumnIndex, FormToolkit toolkit) {
+ super(serverName, statsPeriod, unit, maxValue, columnCount, dataColumnIndex, toolkit);
+ }
+
+ @Override
+ protected void updatePreference(String serverName) {
+ preferenceStore.setValue(PreferenceConstants.P_MEM_CHART_PERIOD, statsPeriod);
+ }
+
+ @Override
+ public ChartPeriodLinkListener getInstance(String statsPeriod) {
+ return new MemoryChartPeriodLinkListener(serverName, statsPeriod, "%", 100, 4, dataColumnIndex, toolkit);
+ }
+ }
+
+ public class NetworkChartPeriodLinkListener extends ChartPeriodLinkListener {
+ private GlusterServer server;
+
+ public NetworkChartPeriodLinkListener(GlusterServer server, String statsPeriod, FormToolkit toolkit) {
+ super(server == null ? null : server.getName(), statsPeriod, toolkit);
+ this.setServer(server);
+ }
+
+ private NetworkChartPeriodLinkListener(GlusterServer server, String statsPeriod, String unit, double maxValue,
+ int columnCount, int dataColumnIndex, FormToolkit toolkit) {
+ super(server == null ? null : server.getName(), statsPeriod, unit, maxValue, columnCount, dataColumnIndex,
+ toolkit);
+ this.setServer(server);
+ }
+
+ @Override
+ protected void updatePreference(String serverName) {
+ if (serverName == null) {
+ preferenceStore.setValue(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD, statsPeriod);
+ } else {
+ preferenceStore.setValue(PreferenceConstants.P_NETWORK_CHART_PERIOD, statsPeriod);
+ }
+ }
+
+ @Override
+ public ChartPeriodLinkListener getInstance(String statsPeriod) {
+ // if serverName is null, it means we are showing aggregated stats - so the "network interface" combo will
+ // not be shown in the "links" composite.
+ int columnCount = (serverName == null ? 4 : 5);
+ return new NetworkChartPeriodLinkListener(server, statsPeriod, "KiB/s", -1d, columnCount, dataColumnIndex,
+ toolkit);
+ }
+
+ public void setServer(GlusterServer server) {
+ this.server = server;
+ }
+
+ public GlusterServer getServer() {
+ return server;
+ }
+ }
+
+ public void createNetworkInterfaceCombo(final Composite section, final Composite graphComposite,
+ final FormToolkit toolkit, final NetworkChartPeriodLinkListener networkChartPeriodLinkListener) {
+ final GlusterServer server = networkChartPeriodLinkListener.getServer();
+ final CCombo interfaceCombo = new CCombo(graphComposite, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER | SWT.FLAT);
+ final List<NetworkInterface> niList = server.getNetworkInterfaces();
+ final String[] interfaces = new String[niList.size()];
+
+ for (int i = 0; i < interfaces.length; i++) {
+ interfaces[i] = niList.get(i).getName();
+ }
+ interfaceCombo.setItems(interfaces);
+ interfaceCombo.select(0);
+ interfaceCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ preferenceStore.setValue(PreferenceConstants.P_DEFAULT_NETWORK_INTERFACE_PFX + server.getName(), interfaces[interfaceCombo.getSelectionIndex()]);
+ }
+ });
+ }
+
+ public void refreshChartSection(FormToolkit toolkit, Composite section, ServerStats stats, String statsPeriod,
+ String unit, double maxValue, int columnCount, ChartPeriodLinkListener linkListener, int dataColumnIndex) {
+ GUIHelper.getInstance().clearSection(section);
+ createAreaChart(toolkit, section, stats, dataColumnIndex, unit, getTimestampFormatForPeriod(statsPeriod),
+ linkListener, maxValue, columnCount);
+ section.layout();
+ }
+
+ public String getTimestampFormatForPeriod(String statsPeriod) {
+ if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1DAY)) {
+ return "HH:mm";
+ } else if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1WEEK)) {
+ return "dd-MMM HH:mm";
+ } else {
+ return "dd-MMM";
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartViewerComposite.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartViewerComposite.java
new file mode 100644
index 00000000..4f2e7ecf
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ChartViewerComposite.java
@@ -0,0 +1,475 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.utils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.birt.chart.api.ChartEngine;
+import org.eclipse.birt.chart.device.IDeviceRenderer;
+import org.eclipse.birt.chart.device.IUpdateNotifier;
+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.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.LineAttributes;
+import org.eclipse.birt.chart.model.attribute.LineStyle;
+import org.eclipse.birt.chart.model.attribute.Position;
+import org.eclipse.birt.chart.model.attribute.Text;
+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.JavaDateFormatSpecifierImpl;
+import org.eclipse.birt.chart.model.attribute.impl.LineAttributesImpl;
+import org.eclipse.birt.chart.model.attribute.impl.NumberFormatSpecifierImpl;
+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.DateTimeDataElement;
+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.DateTimeDataElementImpl;
+import org.eclipse.birt.chart.model.data.impl.DateTimeDataSetImpl;
+import org.eclipse.birt.chart.model.data.impl.NumberDataElementImpl;
+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.PieSeries;
+import org.eclipse.birt.chart.model.type.impl.AreaSeriesImpl;
+import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl;
+import org.eclipse.birt.core.framework.PlatformConfig;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
+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 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(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
+ * 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
+ * @param maxValue
+ */
+ public ChartViewerComposite(Composite parent, int style, Calendar[] categories, Double[] values, String unit, String timestampFormat, double maxValue) {
+ super(parent, style);
+ init();
+
+ createSingleAreaChart(categories, values, unit, timestampFormat, maxValue);
+ 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);
+ }
+
+ addControlListener(new ControlListener() {
+
+ public void controlMoved(ControlEvent e) {
+ needsGeneration = true;
+ }
+
+ public void controlResized(ControlEvent e) {
+ needsGeneration = true;
+ }
+ });
+ }
+
+ private void createSingleAreaChart(Calendar[] timestamps, Double[] values, String unit, String timestampFormat, double maxValue) {
+ createAreaChart(timestamps, new Double[][] {values}, unit, timestampFormat, maxValue);
+ }
+
+ /**
+ * Creates a line chart model as a reference implementation
+ * @param maxValue
+ *
+ * @return An instance of the simulated runtime chart model (containing
+ * filled datasets)
+ */
+ private final void createAreaChart(Calendar[] timestamps, Double[][] values, final String unit, final String timestampFormat, double maxValue) {
+ chart = ChartWithAxesImpl.create();
+ // Plot
+ chart.getBlock().setBackground(ColorDefinitionImpl.WHITE());
+ Plot p = chart.getPlot();
+ p.getClientArea().setBackground(ColorDefinitionImpl.WHITE());
+ p.setBackground(ColorDefinitionImpl.WHITE());
+
+ // Title
+ chart.getTitle().getLabel().getCaption().setValue("Line Chart");//$NON-NLS-1$
+ chart.getTitle().setVisible(false);
+ chart.getTitle().getLabel().setVisible(true);
+ chart.getTitle().getInsets().set(0, 10, 0, 0);
+ chart.getTitle().setAnchor(Anchor.SOUTH_LITERAL);
+
+ // Legend
+ Legend lg = chart.getLegend();
+ lg.setVisible(false);
+ LineAttributes lia = lg.getOutline( );
+ lia.setStyle( LineStyle.SOLID_LITERAL );
+ lg.getText( ).getFont( ).setSize( 10 );
+ //lg.getInsets( ).set( 10, 5, 0, 0 );
+ lg.getInsets( ).set( 0, 0, 0, 0 );
+ lg.getOutline( ).setVisible( false );
+ lg.setAnchor( Anchor.NORTH_LITERAL );
+
+ updateDataSet(timestamps, values, unit, timestampFormat, maxValue);
+ }
+
+ private void updateDataSet(Calendar[] timestamps, Double[][] values, final String unit, final String timestampFormat, double maxValue) {
+ Axis xAxisPrimary = setupXAxis(timestamps, timestampFormat);
+
+ if(maxValue <= 0) {
+ maxValue = getMaxValue(values);
+ }
+ Axis yAxisPrimary = setupYAxis(unit, xAxisPrimary, maxValue);
+ configureXSeries(timestamps, xAxisPrimary);
+ configureYSeries(values, yAxisPrimary);
+ }
+
+ private double getMaxValue(Double[][] values) {
+ double maxValue = -1;
+ for(Double[] seriesValues : values) {
+ double seriesMaxVal = Collections.max(Arrays.asList(seriesValues));
+ if(seriesMaxVal > maxValue) {
+ maxValue = Math.round(seriesMaxVal) + 5 - (Math.round(seriesMaxVal) % 5);
+ }
+ }
+ return maxValue;
+ }
+
+ private void configureYSeries(Double[][] values, Axis yAxisPrimary) {
+ 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(true);
+// }
+ ls.setTranslucent(true);
+ // don't show values on each point on the line chart
+ ls.getLabel().setVisible(false);
+ sdY.getSeries().add(ls);
+ }
+ }
+
+ private void configureXSeries(Calendar[] timestamps, Axis xAxisPrimary) {
+ // 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);
+ }
+
+ private Axis setupYAxis(final String unit, Axis xAxisPrimary, double maxValue) {
+ Axis yAxisPrimary = ((ChartWithAxesImpl)chart).getPrimaryOrthogonalAxis(xAxisPrimary);
+ if(maxValue > 0) {
+ yAxisPrimary.getScale().setMax(NumberDataElementImpl.create(maxValue));
+ yAxisPrimary.getScale().setStep(maxValue / 5);
+ }
+ yAxisPrimary.getScale().setMin(NumberDataElementImpl.create(0));
+ yAxisPrimary.setGapWidth(0);
+ yAxisPrimary.getScale().setMajorGridsStepNumber(1);
+ yAxisPrimary.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL);
+ yAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1));
+ yAxisPrimary.getLabel().setVisible(true);
+ yAxisPrimary.getLabel().getCaption().getFont().setSize(8);
+ yAxisPrimary.setFormatSpecifier(new NumberFormatSpecifierImpl() {
+ @Override
+ public String getSuffix() {
+ return " " + unit;
+ }
+ });
+ return yAxisPrimary;
+ }
+
+ private Axis setupXAxis(Calendar[] timestamps, final String timestampFormat) {
+ Axis xAxisPrimary = ((ChartWithAxesImpl)chart).getPrimaryBaseAxes()[0];
+ xAxisPrimary.setType(AxisType.TEXT_LITERAL);
+ DateTimeDataElement dtde = DateTimeDataElementImpl.create(timestamps[timestamps.length-1]);
+ DateTimeDataElement dtde1 = DateTimeDataElementImpl.create(timestamps[0]);
+ xAxisPrimary.getScale().setMax(dtde);
+ xAxisPrimary.getScale().setStep((dtde.getValue() - dtde1.getValue())/ 10);
+ xAxisPrimary.getScale().setMajorGridsStepNumber(timestamps.length > 10 ? timestamps.length / 10 : 1);
+ //xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.ABOVE_LITERAL);
+ xAxisPrimary.getMajorGrid().getTickAttributes().setVisible(false);
+ xAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1));
+ xAxisPrimary.getTitle().setVisible(false);
+ xAxisPrimary.getTitle().getInsets().set(1, 1, 1, 1);
+ xAxisPrimary.getLabel().getInsets().set(1, 1, 1, 1);
+ //xAxisPrimary.getLabel().getCaption().setFont(createChartFont());
+ xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setSize(8);
+ //commenting to check whether this is causing the problem on windows
+ //xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setRotation( 75 );
+ xAxisPrimary.setFormatSpecifier( JavaDateFormatSpecifierImpl.create( timestampFormat ) );
+ return xAxisPrimary;
+ }
+
+ /**
+ * @param categories
+ * Categories of the pie chart
+ * @param values
+ * 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) {
+ ChartWithoutAxes pieChart = ChartWithoutAxesImpl.create();
+
+ // script hook to NOT show the label if value is zero
+ pieChart.setScript("function beforeDrawDataPointLabel( dph, label, icsc ){ if (dph.getOrthogonalValue() == 0){ label.setVisible(false); } } ");
+
+ // Plot
+ pieChart.setSeriesThickness(10);
+ 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);
+
+ // Legend
+ Legend lg = pieChart.getLegend();
+ lg.setMaxPercent(0.7);
+ lg.getText().getFont().setSize(9);
+ lg.setBackground(null);
+ lg.getOutline().setVisible(false);
+ lg.setVisible(true);
+
+ // Title
+ pieChart.getTitle().getLabel().getCaption().setValue("Pie Chart");//$NON-NLS-1$
+ pieChart.getTitle().getOutline().setVisible(false);
+ pieChart.getTitle().setVisible(false);
+
+ TextDataSet categoryValues = TextDataSetImpl.create(categories);
+ NumberDataSet seriesOneValues = NumberDataSetImpl.create(values);
+
+ // Base Series
+ Series seCategory = SeriesImpl.create();
+ seCategory.setDataSet(categoryValues);
+
+ SeriesDefinition sd = SeriesDefinitionImpl.create();
+ pieChart.getSeriesDefinitions().add(sd);
+ sd.setSeriesPalette(new GlusterChartPalette());
+ sd.getSeriesPalette().shift(0);
+ sd.getSeries().add(seCategory);
+
+ // Orthogonal Series
+ PieSeries sePie = (PieSeries) PieSeriesImpl.create();
+ sePie.setRatio(0.60);
+ sePie.setDataSet(seriesOneValues);
+ sePie.setSeriesIdentifier("Chart");//$NON-NLS-1$
+ sePie.getTitle().setVisible(false); // no title
+ sePie.getLabel().setVisible(true); // show label (values)
+ sePie.setExplosion(0); // no gap between the pie slices
+ sePie.setLabelPosition(Position.INSIDE_LITERAL);
+ Text labelCaption = sePie.getLabel().getCaption();
+ labelCaption.setColor(ColorDefinitionImpl.CYAN());
+ labelCaption.getFont().setSize(8);
+ labelCaption.getFont().setBold(true);
+
+ SeriesDefinition seriesDefinition = SeriesDefinitionImpl.create();
+ seriesDefinition.getQuery().setDefinition("query.definition");//$NON-NLS-1$
+ sd.getSeriesDefinitions().add(seriesDefinition);
+ seriesDefinition.getSeries().add(sePie);
+
+ return pieChart;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events
+ * .PaintEvent)
+ */
+ public final void paintControl(PaintEvent e) {
+ Rectangle d = ((Composite) e.getSource()).getBounds();
+ Image imgChart = new Image(this.getDisplay(), d);
+ GC gcImage = new GC(imgChart);
+ deviceReader.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gcImage);
+ deviceReader.setProperty(IDeviceRenderer.UPDATE_NOTIFIER, this);
+
+ Bounds bo = BoundsImpl.create(0, 0, d.width, d.height);
+ bo.scale(71d / deviceReader.getDisplayServer().getDpiResolution());
+
+ Generator gr = Generator.instance();
+ if (needsGeneration) {
+ needsGeneration = false;
+ try {
+ generatedChartState = gr.build(deviceReader.getDisplayServer(), chart, bo, null, null, null);
+ } catch (ChartException ce) {
+ ce.printStackTrace();
+ }
+ }
+
+ try {
+ gr.render(deviceReader, generatedChartState);
+ 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);
+ }
+ }
+
+// public void chartRefresh(Calendar[] timestamps, Double[][] values, String unit, String timestampFormat)
+// {
+// if ( !isDisposed( ) )
+// {
+// final Generator gr = Generator.instance( );
+// updateDataSet( timestamps, values, unit, timestampFormat);
+//
+// // Refresh
+// try
+// {
+// gr.refresh( generatedChartState );
+// }
+// catch ( ChartException ex )
+// {
+// // TODO: log the exception
+// ex.printStackTrace( );
+// }
+// redraw( );
+// }
+// }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.device.IUpdateNotifier#getDesignTimeModel()
+ */
+ public Chart getDesignTimeModel() {
+ return chart;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.device.IUpdateNotifier#getRunTimeModel()
+ */
+ public Chart getRunTimeModel() {
+ return generatedChartState.getChartModel();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.device.IUpdateNotifier#peerInstance()
+ */
+ public Object peerInstance() {
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.device.IUpdateNotifier#regenerateChart()
+ */
+ public void regenerateChart() {
+ redraw();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.device.IUpdateNotifier#repaintChart()
+ */
+ public void repaintChart() {
+ redraw();
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/EntityViewerFilter.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/EntityViewerFilter.java
new file mode 100644
index 00000000..2ee6d535
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/EntityViewerFilter.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.utils;
+
+import java.util.Map.Entry;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.gluster.storage.management.core.model.Filterable;
+import org.gluster.storage.management.core.utils.StringUtil;
+
+
+public class EntityViewerFilter extends ViewerFilter {
+
+ private String filterString;
+ private boolean caseSensitive = false;
+
+ public EntityViewerFilter(String filterString, boolean caseSensitive) {
+ this.filterString = filterString;
+ this.caseSensitive = caseSensitive;
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ public void setCaseSensitive(boolean caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ }
+
+ public String getFilterString() {
+ return filterString;
+ }
+
+ public void setFilterString(String filterString) {
+ this.filterString = filterString;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (filterString == null || filterString.isEmpty()) {
+ // No filter string. select everything
+ return true;
+ }
+
+ if (element instanceof Filterable) {
+ return ((Filterable) element).filter(filterString, caseSensitive);
+ }
+
+ if(element instanceof Entry) {
+ Entry<String, String> entry = (Entry<String, String>)element;
+ return StringUtil.filterString(entry.getKey() + entry.getValue(), filterString, caseSensitive);
+ }
+
+ if(element instanceof String) {
+ return StringUtil.filterString((String)element, filterString, caseSensitive);
+ }
+
+ return false;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GUIHelper.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GUIHelper.java
new file mode 100644
index 00000000..600a941c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GUIHelper.java
@@ -0,0 +1,481 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.utils;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLayoutData;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.ColumnLayout;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.gluster.storage.management.console.Application;
+import org.gluster.storage.management.console.ConsoleConstants;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.views.NavigationView;
+import org.gluster.storage.management.console.views.TasksView;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.utils.JavaUtil;
+
+
+public class GUIHelper {
+ private static final GUIHelper instance = new GUIHelper();
+ private static final ImageUtil imageUtil = new ImageUtil();
+ private static final GlusterLogger logger = GlusterLogger.getInstance();
+
+ private GUIHelper() {
+
+ }
+
+ public static GUIHelper getInstance() {
+ return instance;
+ }
+
+ public ScrolledForm setupForm(Composite parent, FormToolkit toolkit, final String formName) {
+ return setupForm(toolkit, formName, toolkit.createScrolledForm(parent));
+ }
+
+ public ScrolledForm setupForm(FormToolkit toolkit, final String formName, ScrolledForm form) {
+ form.setText(formName);
+ toolkit.decorateFormHeading(form.getForm());
+
+ ColumnLayout layout = new ColumnLayout();
+
+ // layout.topMargin = 0;
+ // layout.bottomMargin = 5;
+ // layout.leftMargin = 10;
+ // layout.rightMargin = 10;
+ // layout.horizontalSpacing = 10;
+ // layout.verticalSpacing = 10;
+ // layout.maxNumColumns = 4;
+ // layout.minNumColumns = 1;
+
+ form.getBody().setLayout(layout);
+ return form;
+ }
+
+ public Composite createSection(final ScrolledForm form, FormToolkit toolkit, String title, String desc,
+ int numColumns, boolean collapsible) {
+ int style = Section.TITLE_BAR | Section.EXPANDED;
+ if (desc != null && !desc.isEmpty()) {
+ style |= Section.DESCRIPTION;
+ }
+ if (collapsible) {
+ style |= Section.TWISTIE;
+ }
+
+ Section section = toolkit.createSection(form.getBody(), style);
+ section.setText(title);
+ section.setDescription(desc);
+
+ // toolkit.createCompositeSeparator(section);
+ Composite client = toolkit.createComposite(section);
+ GridLayout layout = new GridLayout();
+ layout.marginWidth = layout.marginHeight = 0;
+ layout.numColumns = numColumns;
+ layout.verticalSpacing = 10;
+ layout.marginBottom = 15;
+ layout.marginTop = 10;
+
+ client.setLayout(layout);
+ section.setClient(client);
+
+ section.addExpansionListener(new ExpansionAdapter() {
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(false);
+ }
+ });
+ return client;
+ }
+
+ public Composite createTab(TabFolder tabFolder, String title, String imageKey) {
+ TabItem item = new TabItem(tabFolder, SWT.NONE);
+ item.setText(title);
+ item.setImage(getImage(imageKey));
+
+ Composite composite = new Composite(tabFolder, SWT.NONE);
+ composite.setLayout(new FillLayout());
+
+ item.setControl(composite);
+
+ return composite;
+ }
+
+ public ImageDescriptor getImageDescriptor(String imagePath) {
+ return imageUtil.getImageDescriptor(imagePath);
+ }
+
+ public Image getImage(String imagePath) {
+ return imageUtil.getImage(imagePath);
+ }
+
+ public Action createPullDownMenu(String menuName, String iconPath, final MenuManager menuManager) {
+ Action action = new Action(menuName, IAction.AS_DROP_DOWN_MENU) {
+ public void run() {
+ }
+ };
+ action.setMenuCreator(new IMenuCreator() {
+
+ @Override
+ public Menu getMenu(Menu menu) {
+ return null;
+ }
+
+ @Override
+ public Menu getMenu(Control control) {
+ return menuManager.createContextMenu(control);
+ }
+
+ @Override
+ public void dispose() {
+ }
+ });
+ action.setImageDescriptor(getImageDescriptor(iconPath));
+ return action;
+ }
+
+ public TableColumnLayout createTableColumnLayout(Table table, String[] columns) {
+ TableColumnLayout tableColumnLayout = new TableColumnLayout();
+ ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100);
+
+ for (String columnName : columns) {
+ TableColumn column = new TableColumn(table, SWT.LEFT);
+ column.setText(columnName);
+
+ tableColumnLayout.setColumnData(column, defaultColumnLayoutData);
+ }
+
+ return tableColumnLayout;
+ }
+
+ /**
+ * Creates a filter for given structured viewer that will filter the contents of the viewer based on the current
+ * text of the text field
+ *
+ * @param viewer
+ * Structured viewer for which the filter is to be created
+ * @param filterText
+ * The text field whose contents are to be used for filtering
+ * @param caseSensitive
+ * Flag indicating whether the filtering should be case sensitive
+ * @return The newly created filter
+ */
+ public EntityViewerFilter createFilter(final StructuredViewer viewer, final Text filterText, boolean caseSensitive) {
+ final String initialFilterString = filterText.getText();
+
+ final EntityViewerFilter filter = new EntityViewerFilter(initialFilterString, caseSensitive);
+ // On every keystroke inside the text field, update the filter string
+ filterText.addKeyListener(new KeyAdapter() {
+ private String filterString = initialFilterString;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ String enteredString = filterText.getText();
+ if (enteredString.equals(filterString)) {
+ // Filter string has not changed. don't do anything
+ return;
+ }
+
+ // Update filter string
+ filterString = enteredString;
+ filter.setFilterString(filterString);
+
+ // Refresh viewer with newly filtered content
+ viewer.refresh(true);
+ if(viewer instanceof TreeViewer) {
+ ((TreeViewer)viewer).expandAll();
+ }
+ }
+ });
+
+ viewer.addFilter(filter);
+ return filter;
+ }
+
+ public IViewPart getView(String viewId) {
+ IViewReference[] views = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+ .getViewReferences();
+ for (IViewReference view : views) {
+ if (view.getId().equals(viewId)) {
+ return view.getView(false);
+ }
+ }
+ return null;
+ }
+
+ public IWorkbenchPart getActiveView() {
+ return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
+ }
+
+ public ControlDecoration createErrorDecoration(Control control) {
+ ControlDecoration passwordErrorDecoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
+ passwordErrorDecoration.setImage(FieldDecorationRegistry.getDefault()
+ .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage());
+ return passwordErrorDecoration;
+ }
+
+ public void centerShellInScreen(Shell shell) {
+ Rectangle monitorBounds = shell.getMonitor().getBounds();
+ Rectangle myBounds = shell.getBounds();
+
+ int x = monitorBounds.x + (monitorBounds.width - myBounds.width) / 2;
+ int y = monitorBounds.y + (monitorBounds.height - myBounds.height) / 2;
+ shell.setLocation(x, y);
+ }
+
+ public Text createFilterText(FormToolkit toolkit, Composite parent) {
+ final String tooltipMessage = "Start typing to filter table contents.";
+ final Text filterText = toolkit.createText(parent, "", SWT.FLAT);
+
+ GridData data = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
+ data.widthHint = 300;
+ filterText.setLayoutData(data);
+
+ ControlDecoration searchDecoration = new ControlDecoration(filterText, SWT.LEFT);
+ searchDecoration.setImage(getImage(IImageKeys.SEARCH_22x22));
+ searchDecoration.show();
+ searchDecoration.setShowHover(true);
+ searchDecoration.setDescriptionText(tooltipMessage);
+ searchDecoration.setMarginWidth(5);
+
+ filterText.setToolTipText(tooltipMessage);
+ return filterText;
+ }
+
+ public Text createFilterText(Composite parent) {
+ final String tooltipMessage = "Start typing to filter table contents.";
+ final Text filterText = new Text(parent, SWT.FLAT);
+
+ GridData data = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ data.widthHint = 300;
+ filterText.setLayoutData(data);
+
+ ControlDecoration searchDecoration = new ControlDecoration(filterText, SWT.RIGHT);
+ searchDecoration.setImage(getImage(IImageKeys.SEARCH_22x22));
+ searchDecoration.show();
+ searchDecoration.setShowHover(true);
+ searchDecoration.setDescriptionText(tooltipMessage);
+
+ filterText.setToolTipText(tooltipMessage);
+ return filterText;
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ public void setColumnProperties(Table table, int columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex);
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ /**
+ * Fetches the currently selected objects from the workbench site and returns the one of given type. If none of the
+ * selected objects are of given type, returns null
+ *
+ * @param site
+ * The workbench site
+ * @param expectedType
+ * Type of the selected object to look for
+ * @return The selected object of given type if found, else null
+ */
+ public <T> T getSelectedEntity(IWorkbenchSite site, Class<T> expectedType) {
+ return getSelectedEntity(site.getWorkbenchWindow(), expectedType);
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ public <T> T getSelectedEntity(IWorkbenchWindow window, Class<T> expectedType) {
+ ISelection selection = window.getSelectionService().getSelection(NavigationView.ID);
+ if (selection instanceof IStructuredSelection) {
+ Iterator<Object> iter = ((IStructuredSelection) selection).iterator();
+ while (iter.hasNext()) {
+ Object selectedObj = iter.next();
+ if (selectedObj.getClass() == expectedType) {
+ return (T)selectedObj;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Fetches the currently selected objects from the workbench site and returns those of given type. If none of the
+ * selected objects are of given type, returns null
+ *
+ * @param site
+ * The workbench site
+ * @param expectedType
+ * Type of the selected objects to look for
+ * @return The selected objects of given type if found, else null
+ */
+ public <T> Set<T> getSelectedEntities(IWorkbenchSite site, Class<T> expectedType) {
+ return getSelectedEntities(site.getWorkbenchWindow(), expectedType);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> Set<T> getSelectedEntities(IWorkbenchWindow window, Class<T> expectedType) {
+ Set<T> selectedEntities = new HashSet<T>();
+ ISelection selection = window.getSelectionService().getSelection();
+ if (selection instanceof IStructuredSelection) {
+ Iterator<Object> iter = ((IStructuredSelection) selection).iterator();
+ while (iter.hasNext()) {
+ Object selectedObj = iter.next();
+ if (selectedObj.getClass() == expectedType) {
+ selectedEntities.add((T) selectedObj);
+ }
+ }
+ }
+ return selectedEntities;
+ }
+
+
+ public void configureCheckboxTableViewer(final CheckboxTableViewer tableViewer) {
+ tableViewer.addCheckStateListener(new ICheckStateListener() {
+
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ tableViewer.setSelection(new StructuredSelection(tableViewer.getCheckedElements()));
+ }
+ });
+
+ tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ List<Object> checkedElements = Arrays.asList(tableViewer.getCheckedElements());
+ List<Object> selectedElements = ((IStructuredSelection)event.getSelection()).toList();
+
+ if (JavaUtil.listsDiffer(checkedElements, selectedElements)) {
+ tableViewer.setSelection(new StructuredSelection(tableViewer.getCheckedElements()));
+ }
+ }
+ });
+ }
+
+ public void showView(String viewId) {
+ try {
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(viewId);
+ } catch (PartInitException e) {
+ String errMsg = "Could not open view [" + viewId + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ public void showTerminalView() {
+ showView(ConsoleConstants.TERMINAL_VIEW_ID);
+ }
+
+ public void showProgressView() {
+ showView(IProgressConstants.PROGRESS_VIEW_ID);
+ }
+
+ public void showTaskView() {
+ NavigationView navigationView = (NavigationView) getView(NavigationView.ID);
+ navigationView.selectEntity(GlusterDataModelManager.getInstance().getModel().getCluster());
+
+ showView(TasksView.ID);
+ }
+
+ public void setStatusMessage(String message) {
+ clearStatusMessage();
+ Application.getApplication().getStatusLineManager().setMessage(message);
+ Application.getApplication().getStatusLineManager().setMessage(message);
+ }
+
+ public void clearStatusMessage() {
+ Application.getApplication().getStatusLineManager().setMessage(null);
+ }
+
+ public String getDiskToolTip(Disk disk) {
+ return disk.getQualifiedName() + " - " + disk.getDescription();
+ }
+
+ public void clearSection(Composite section) {
+ if (section.isDisposed()) {
+ return;
+ }
+ for(Control control : section.getChildren()) {
+ if(! control.isDisposed()) {
+ control.dispose();
+ }
+ }
+ section.layout(true);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterChartPalette.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterChartPalette.java
new file mode 100644
index 00000000..4c579103
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterChartPalette.java
@@ -0,0 +1,479 @@
+/***********************************************************************
+ * Copyright (c) 2004 Actuate Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Actuate Corporation - initial API and implementation
+ ***********************************************************************/
+
+package org.gluster.storage.management.console.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.birt.chart.engine.i18n.Messages;
+import org.eclipse.birt.chart.log.ILogger;
+import org.eclipse.birt.chart.log.Logger;
+import org.eclipse.birt.chart.model.attribute.AttributeFactory;
+import org.eclipse.birt.chart.model.attribute.AttributePackage;
+import org.eclipse.birt.chart.model.attribute.ColorDefinition;
+import org.eclipse.birt.chart.model.attribute.Fill;
+import org.eclipse.birt.chart.model.attribute.Palette;
+import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
+import org.eclipse.emf.ecore.impl.EObjectImpl;
+import org.eclipse.emf.ecore.util.EObjectContainmentEList;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import com.ibm.icu.util.ULocale;
+
+/**
+ * <!-- begin-user-doc --> An implementation of the model object '
+ * <em><b>Palette</b></em>'. <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * <ul>
+ * <li>{@link org.eclipse.birt.chart.model.attribute.impl.GlusterChartPalette#getName <em>Name</em>}</li>
+ * <li>{@link org.eclipse.birt.chart.model.attribute.impl.GlusterChartPalette#getEntries <em>Entries</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @generated
+ */
+public class GlusterChartPalette extends EObjectImpl implements Palette
+{
+
+ /**
+ * The default value of the '{@link #getName() <em>Name</em>}' attribute.
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @see #getName()
+ * @generated
+ * @ordered
+ */
+ protected static final String NAME_EDEFAULT = null;
+
+ /**
+ * The cached value of the '{@link #getName() <em>Name</em>}' attribute.
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @see #getName()
+ * @generated
+ * @ordered
+ */
+ protected String name = NAME_EDEFAULT;
+
+ /**
+ * The cached value of the '{@link #getEntries() <em>Entries</em>}' containment reference list.
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @see #getEntries()
+ * @generated
+ * @ordered
+ */
+ protected EList<Fill> entries;
+
+ private static ILogger logger = Logger.getLogger( "org.eclipse.birt.chart.engine/model.attribute.impl" ); //$NON-NLS-1$
+
+ private static List colorLib = new ArrayList( 32 );
+ static
+ {
+ colorLib.add( ColorDefinitionImpl.create ( 0, 1, 252) );
+ colorLib.add( ColorDefinitionImpl.create ( 255, 0, 255) );
+ //colorLib.add( ColorDefinitionImpl.BLUE() );
+ //colorLib.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ public GlusterChartPalette( )
+ {
+ super( );
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ protected EClass eStaticClass( )
+ {
+ return AttributePackage.Literals.PALETTE;
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ public String getName( )
+ {
+ return name;
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ public void setName( String newName )
+ {
+ String oldName = name;
+ name = newName;
+ if ( eNotificationRequired( ) )
+ eNotify( new ENotificationImpl( this,
+ Notification.SET,
+ AttributePackage.PALETTE__NAME,
+ oldName,
+ name ) );
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ public EList<Fill> getEntries( )
+ {
+ if ( entries == null )
+ {
+ entries = new EObjectContainmentEList<Fill>( Fill.class,
+ this,
+ AttributePackage.PALETTE__ENTRIES );
+ }
+ return entries;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public NotificationChain eInverseRemove( InternalEObject otherEnd,
+ int featureID, NotificationChain msgs )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__ENTRIES :
+ return ( (InternalEList<?>) getEntries( ) ).basicRemove( otherEnd,
+ msgs );
+ }
+ return super.eInverseRemove( otherEnd, featureID, msgs );
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public Object eGet( int featureID, boolean resolve, boolean coreType )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ return getName( );
+ case AttributePackage.PALETTE__ENTRIES :
+ return getEntries( );
+ }
+ return super.eGet( featureID, resolve, coreType );
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void eSet( int featureID, Object newValue )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ setName( (String) newValue );
+ return;
+ case AttributePackage.PALETTE__ENTRIES :
+ getEntries( ).clear( );
+ getEntries( ).addAll( (Collection<? extends Fill>) newValue );
+ return;
+ }
+ super.eSet( featureID, newValue );
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public void eUnset( int featureID )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ setName( NAME_EDEFAULT );
+ return;
+ case AttributePackage.PALETTE__ENTRIES :
+ getEntries( ).clear( );
+ return;
+ }
+ super.eUnset( featureID );
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public boolean eIsSet( int featureID )
+ {
+ switch ( featureID )
+ {
+ case AttributePackage.PALETTE__NAME :
+ return NAME_EDEFAULT == null ? name != null
+ : !NAME_EDEFAULT.equals( name );
+ case AttributePackage.PALETTE__ENTRIES :
+ return entries != null && !entries.isEmpty( );
+ }
+ return super.eIsSet( featureID );
+ }
+
+ /**
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public String toString( )
+ {
+ if ( eIsProxy( ) )
+ return super.toString( );
+
+ StringBuffer result = new StringBuffer( super.toString( ) );
+ result.append( " (name: " ); //$NON-NLS-1$
+ result.append( name );
+ result.append( ')' );
+ return result.toString( );
+ }
+
+ /**
+ * A convenience method provided to create an empty or pre-initialized
+ * palette
+ *
+ * NOTE: Manually written
+ *
+ * @param bEmpty
+ */
+ public static final Palette create( int iIndex, boolean bEmpty )
+ {
+ final Palette p = AttributeFactory.eINSTANCE.createPalette( );
+
+ if ( !bEmpty )
+ {
+ p.shift( iIndex );
+ }
+ return p;
+ }
+
+ /**
+ * A convenience method provided to create a palette with a single color
+ * entry
+ *
+ * NOTE: Manually written
+ *
+ * @param f
+ */
+ public static final Palette create( Fill f )
+ {
+ final Palette p = AttributeFactory.eINSTANCE.createPalette( );
+ p.getEntries( ).add( f );
+ return p;
+ }
+
+ /**
+ * Shift the list content from tail to head.
+ *
+ * @param lst
+ * @param pos
+ */
+ private static final void shiftList( final List lst, int pos )
+ {
+ int size = lst.size( );
+
+ if ( pos < 1 )
+ {
+ pos = 0;
+ }
+
+ if ( pos >= size )
+ {
+ pos = pos % size;
+ }
+
+ if ( pos == 0 )
+ {
+ return;
+ }
+
+ Object[] array = lst.toArray( );
+
+ lst.clear( );
+
+ for ( int i = pos; i < array.length; i++ )
+ {
+ lst.add( array[i] );
+ }
+
+ for ( int i = 0; i < pos; i++ )
+ {
+ lst.add( array[i] );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.model.attribute.Palette#update(int)
+ */
+ public final void update( int iIndex )
+ {
+ final EList el = getEntries( );
+ el.clear( );
+ if ( iIndex < 0 )
+ {
+ // a rotation version of palette-0, rataion pos is the negatvie
+ // index.
+ ArrayList al = new ArrayList( );
+
+ al.add( ColorDefinitionImpl.create( 80, 166, 218 ) );
+ al.add( ColorDefinitionImpl.create( 242, 88, 106 ) );
+ al.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ al.add( ColorDefinitionImpl.create( 128, 255, 128 ) );
+ al.add( ColorDefinitionImpl.create( 64, 128, 128 ) );
+ al.add( ColorDefinitionImpl.create( 128, 128, 192 ) );
+ al.add( ColorDefinitionImpl.create( 170, 85, 85 ) );
+ al.add( ColorDefinitionImpl.create( 128, 128, 0 ) );
+
+ shiftList( al, -iIndex );
+
+ el.addAll( al );
+ }
+ else if ( iIndex == 0 )
+ {
+ el.add( ColorDefinitionImpl.create( 80, 166, 218 ) );
+ el.add( ColorDefinitionImpl.create( 242, 88, 106 ) );
+ el.add( ColorDefinitionImpl.create( 232, 172, 57 ) );
+ el.add( ColorDefinitionImpl.create( 128, 255, 128 ) );
+ el.add( ColorDefinitionImpl.create( 64, 128, 128 ) );
+ el.add( ColorDefinitionImpl.create( 128, 128, 192 ) );
+ el.add( ColorDefinitionImpl.create( 170, 85, 85 ) );
+ el.add( ColorDefinitionImpl.create( 128, 128, 0 ) );
+ }
+ else if ( iIndex == 1 )
+ {
+ el.add( ColorDefinitionImpl.create( 225, 225, 255 ) );
+ el.add( ColorDefinitionImpl.create( 223, 197, 41 ) );
+ el.add( ColorDefinitionImpl.create( 249, 225, 191 ) );
+ el.add( ColorDefinitionImpl.create( 255, 205, 225 ) );
+ el.add( ColorDefinitionImpl.create( 225, 255, 225 ) );
+ el.add( ColorDefinitionImpl.create( 255, 191, 255 ) );
+ el.add( ColorDefinitionImpl.create( 185, 185, 221 ) );
+ el.add( ColorDefinitionImpl.create( 40, 255, 148 ) );
+ }
+ else
+ {
+ logger.log( ILogger.WARNING,
+ Messages.getString( "error.unknown.palette", //$NON-NLS-1$
+ new Object[]{
+ Integer.valueOf( iIndex )
+ },
+ ULocale.getDefault( ) ) );
+ update( 0 );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.birt.chart.model.attribute.Palette#update(org.eclipse.birt.chart.model.attribute.Fill)
+ */
+ public final void update( Fill f )
+ {
+ final EList el = getEntries( );
+ el.clear( );
+ el.add( f );
+ }
+
+ public void shift( int step )
+ {
+ shift( step, colorLib.size( ) );
+ }
+
+ public void shift( int step, int size )
+ {
+ if ( size <= 0 || size > colorLib.size( ) )
+ {
+ size = colorLib.size( );
+ }
+
+ final EList<Fill> el = getEntries( );
+ el.clear( );
+
+ if ( step == 0 || Math.abs( step ) >= size )
+ {
+ // Do nothing
+ step = 0;
+ }
+ else if ( step < 0 )
+ {
+ // Move to the left side
+ step = -step;
+ }
+ else if ( step > 0 )
+ {
+ // Move to the right side
+ step = size - step;
+ }
+
+ for ( int i = step; i < size; i++ )
+ {
+ el.add( ( (ColorDefinition) colorLib.get( i ) ).copyInstance( ) );
+ }
+ for ( int i = 0; i < step; i++ )
+ {
+ el.add( ( (ColorDefinition) colorLib.get( i ) ).copyInstance( ) );
+ }
+ }
+
+ /**
+ * A convenient method to get an instance copy. This is much faster than the
+ * ECoreUtil.copy().
+ */
+ public Palette copyInstance( )
+ {
+ GlusterChartPalette dest = new GlusterChartPalette( );
+ dest.set( this );
+ return dest;
+ }
+
+ protected void set( Palette src )
+ {
+ if ( src.getEntries( ) != null )
+ {
+ EList<Fill> list = getEntries( );
+ for ( Fill element : src.getEntries( ) )
+ {
+ list.add( element.copyInstance( ) );
+ }
+ }
+ name = src.getName( );
+ }
+
+} // GlusterChartPalette
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterLogger.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterLogger.java
new file mode 100644
index 00000000..4a2ba53b
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/GlusterLogger.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.utils;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.Status;
+import org.gluster.storage.management.console.Activator;
+
+
+/**
+ *
+ */
+public class GlusterLogger {
+ private static final ILog log = Activator.getDefault().getLog();
+ private static GlusterLogger instance = new GlusterLogger();
+
+ private GlusterLogger() {
+ }
+
+ public static GlusterLogger getInstance() {
+ return instance;
+ }
+
+ private void log(String message, int severity, Throwable t) {
+ log.log(new Status(severity, Activator.PLUGIN_ID, message, t));
+ }
+
+ public void error(String message) {
+ log(message, Status.ERROR, null);
+ }
+
+ public void error(String message, Throwable t) {
+ log(message, Status.ERROR, t);
+ }
+
+ public void warn(String message) {
+ log(message, Status.WARNING, null);
+ }
+
+ public void warn(String message, Throwable t) {
+ log(message, Status.WARNING, t);
+ }
+
+ public void info(String message) {
+ log(message, Status.INFO, null);
+ }
+
+ public void info(String message, Throwable t) {
+ log(message, Status.INFO, t);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ImageUtil.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ImageUtil.java
new file mode 100644
index 00000000..eb4a31b9
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/ImageUtil.java
@@ -0,0 +1,52 @@
+/**
+ * ImageUtil.java
+ *
+ * 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 org.gluster.storage.management.console.utils;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.gluster.storage.management.console.Application;
+import org.gluster.storage.management.core.utils.LRUCache;
+
+
+/**
+ *
+ */
+public class ImageUtil {
+ private static final LRUCache<String, Image> imageCache = new LRUCache<String, Image>(20);
+
+ public ImageDescriptor getImageDescriptor(String imagePath) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID, imagePath);
+ }
+
+ public synchronized Image getImage(String imagePath) {
+ if(imageCache.containsKey(imagePath)) {
+ return imageCache.get(imagePath);
+ }
+ return createImage(imagePath);
+ }
+
+ private Image createImage(String imagePath) {
+ Image image = getImageDescriptor(imagePath).createImage();
+ imageCache.put(imagePath, image);
+ return image;
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/TableViewerComparator.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/TableViewerComparator.java
new file mode 100644
index 00000000..9df3942a
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/utils/TableViewerComparator.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 org.gluster.storage.management.console.utils;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+
+/**
+ * Comparator for sorting contents of a table viewer
+ */
+public class TableViewerComparator extends ViewerComparator {
+ private int column = -1;
+ private static final int ASCENDING = 0;
+ private static final int DESCENDING = 1;
+ private static final int NONE = -1;
+ private int direction = DESCENDING;
+
+ public TableViewerComparator() {
+ this(NONE);
+ }
+
+ public TableViewerComparator(int direction) {
+ this.direction = direction;
+ }
+
+ public int getDirection() {
+ return direction == DESCENDING ? SWT.DOWN : (direction == ASCENDING ? SWT.UP : SWT.NONE);
+ }
+
+ public void setColumn(int column) {
+ if (column == this.column) {
+ // Same column as last sort; toggle the direction
+ direction = 1 - direction;
+ } else {
+ // first column selection or new column; do an ascending sort
+ direction = ASCENDING;
+ this.column = column;
+ }
+ }
+
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if(direction == NONE) {
+ // no sorting
+ return 0;
+ }
+
+ int result = super.compare(viewer, e1, e2);
+ // If descending order, flip the direction
+ if (direction == DESCENDING) {
+ result = -result;
+ }
+
+ return result;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/validators/StringRequiredValidator.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/validators/StringRequiredValidator.java
new file mode 100644
index 00000000..5d364606
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/validators/StringRequiredValidator.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.validators;
+
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.swt.widgets.Control;
+
+public class StringRequiredValidator implements IValidator {
+ protected final String errorText;
+ protected final ControlDecoration controlDecoration;
+ protected final Control linkedControl;
+
+ public StringRequiredValidator(String errorText, ControlDecoration controlDecoration, Control linkedControl) {
+ super();
+ this.errorText = errorText;
+ this.controlDecoration = controlDecoration;
+ this.linkedControl = linkedControl;
+ }
+
+ public StringRequiredValidator(String errorText, ControlDecoration controlDecoration) {
+ this(errorText, controlDecoration, null);
+ }
+
+ public IStatus validate(Object value) {
+ if (value instanceof String) {
+ if (((String) value).isEmpty()) {
+ controlDecoration.setDescriptionText(errorText);
+ controlDecoration.show();
+ if (linkedControl != null) {
+ linkedControl.setEnabled(false);
+ }
+ return ValidationStatus.error(errorText);
+ }
+ }
+ if(linkedControl != null) {
+ linkedControl.setEnabled(true);
+ }
+ controlDecoration.hide();
+ return Status.OK_STATUS;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterAdapterFactory.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterAdapterFactory.java
new file mode 100644
index 00000000..a830d4ea
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterAdapterFactory.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.gluster.storage.management.console.Application;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterDataModel;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class ClusterAdapterFactory implements IAdapterFactory {
+ private IWorkbenchAdapter entityAdapter = new IWorkbenchAdapter() {
+
+ @Override
+ public Object getParent(Object o) {
+ return ((Entity) o).getParent();
+ }
+
+ @Override
+ public String getLabel(Object o) {
+ return ((Entity)o).getName();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public ImageDescriptor getImageDescriptor(Object object) {
+ String iconPath = null;
+
+ if(object instanceof GlusterDataModel || object instanceof Cluster) {
+ iconPath = IImageKeys.CLUSTER_16x16;
+ }
+
+ if(object instanceof EntityGroup) {
+ Class<? extends Entity> entityType = ((EntityGroup) object).getEntityType();
+ if(entityType == Volume.class) {
+ iconPath = IImageKeys.VOLUMES_16x16;
+ } else {
+ iconPath = IImageKeys.SERVERS_16x16;
+ }
+ }
+
+ if(object instanceof Volume) {
+ iconPath = IImageKeys.VOLUME_16x16;
+ }
+
+ if(object instanceof Server || object instanceof GlusterServer) {
+ iconPath = IImageKeys.SERVER_16x16;
+ }
+
+ return AbstractUIPlugin.imageDescriptorFromPlugin(
+ Application.PLUGIN_ID, iconPath);
+ }
+
+ @Override
+ public Object[] getChildren(Object o) {
+ return ((Entity)o).getChildren().toArray();
+ }
+ };
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if (adapterType == IWorkbenchAdapter.class) {
+ if (adaptableObject instanceof Entity) {
+ return entityAdapter;
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Class[] getAdapterList() {
+ return new Class[] { IWorkbenchAdapter.class };
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterSummaryView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterSummaryView.java
new file mode 100644
index 00000000..41d2daa7
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ClusterSummaryView.java
@@ -0,0 +1,469 @@
+/**
+ * DiscoveredServerView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import java.util.List;
+
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ImageHyperlink;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.Activator;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.actions.ActionConstants;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.console.utils.ChartUtil;
+import org.gluster.storage.management.console.utils.ChartViewerComposite;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.utils.ChartUtil.ChartPeriodLinkListener;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterDataModel;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+
+
+/**
+ *
+ */
+public class ClusterSummaryView extends ViewPart {
+ public static final String ID = ClusterSummaryView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private Cluster cluster;
+ private Composite cpuChartSection;
+ private Composite networkChartSection;
+ private GlusterDataModel model = GlusterDataModelManager.getInstance().getModel();
+ private ClusterListener clusterListener;
+ private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ private Composite alertsSection;
+ private Composite tasksSection;
+ private static final ChartUtil chartUtil = ChartUtil.getInstance();
+ private IPropertyChangeListener propertyChangeListener;
+ private Label onlineServerCountLabel;
+ private Label offlineServerCountLabel;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ if (cluster == null) {
+ cluster = model.getCluster();
+ }
+ setPartName("Summary");
+ createSections(parent);
+
+ createListeners();
+ }
+
+ private void createListeners() {
+ createClusterListener();
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ createPropertyChangeListener();
+ preferenceStore.addPropertyChangeListener(propertyChangeListener );
+ }
+
+ private void createPropertyChangeListener() {
+ propertyChangeListener = new IPropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ String preferenceName = event.getProperty();
+ GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ if(preferenceName.equals(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD)) {
+ modelManager.initializeAggregatedCpuStats(cluster);
+ String cpuStatsPeriod = (String)event.getNewValue();
+ refreshChartSection(cpuChartSection, cluster.getAggregatedCpuStats(), cpuStatsPeriod, "%", 100, 4,
+ chartUtil.new CpuChartPeriodLinkListener(null, cpuStatsPeriod, toolkit), 2);
+ } else if(preferenceName.equals(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD)) {
+ modelManager.initializeAggregatedNetworkStats(cluster);
+ String networkStatsPeriod = (String)event.getNewValue();
+ refreshChartSection(networkChartSection, cluster.getAggregatedNetworkStats(), networkStatsPeriod, "KiB/s", -1,
+ 4, chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), 2);
+ }
+ }
+ };
+ }
+
+ private void createClusterListener() {
+ clusterListener = new DefaultClusterListener() {
+ @Override
+ public void aggregatedStatsChanged() {
+ super.aggregatedStatsChanged();
+ refreshCharts();
+ populateOnlineOfflineServerCount();
+ }
+
+ @Override
+ public void alertsGenerated() {
+ super.alertsGenerated();
+ guiHelper.clearSection(alertsSection);
+ populateAlerts();
+ }
+
+ @Override
+ public void taskAdded(TaskInfo taskInfo) {
+ super.taskAdded(taskInfo);
+ updateTaskSection();
+ }
+
+ @Override
+ public void taskRemoved(TaskInfo taskInfo) {
+ super.taskRemoved(taskInfo);
+ updateTaskSection();
+ }
+
+ @Override
+ public void taskUpdated(TaskInfo taskInfo) {
+ super.taskUpdated(taskInfo);
+ updateTaskSection();
+ }
+
+ private void updateTaskSection() {
+ guiHelper.clearSection(tasksSection);
+ populateTasksSection();
+ }
+ };
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ preferenceStore.removePropertyChangeListener(propertyChangeListener);
+ }
+
+ private void refreshCharts() {
+ String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD);
+ String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD);
+ refreshChartSection(cpuChartSection, cluster.getAggregatedCpuStats(), cpuStatsPeriod, "%", 100, 4,
+ chartUtil.new CpuChartPeriodLinkListener(null, cpuStatsPeriod, toolkit), 2);
+ refreshChartSection(networkChartSection, cluster.getAggregatedNetworkStats(), networkStatsPeriod, "KiB/s", -1,
+ 4, chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), 2);
+ }
+
+ private int getServerCountByStatus(Cluster cluster, SERVER_STATUS status) {
+ int count = 0;
+ for (GlusterServer server : cluster.getServers()) {
+ if (server.getStatus() == status) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private void createServersSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Servers", null, 2, false);
+ toolkit.createLabel(section, "Online : ");
+ onlineServerCountLabel = toolkit.createLabel(section, "");
+
+ toolkit.createLabel(section, "Offline : ");
+ offlineServerCountLabel = toolkit.createLabel(section, "");
+ populateOnlineOfflineServerCount();
+ }
+
+ private void populateOnlineOfflineServerCount() {
+ int onlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.ONLINE);
+ int offlineServerCount = getServerCountByStatus(cluster, SERVER_STATUS.OFFLINE);
+ onlineServerCountLabel.setText("" + onlineServerCount);
+ onlineServerCountLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN));
+ offlineServerCountLabel.setText("" + offlineServerCount);
+ offlineServerCountLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+ }
+
+
+ private void createDiskSpaceSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Disk Space", null, 3, false);
+ if (cluster.getServers().size() == 0) {
+ toolkit.createLabel(section, "This section will be populated after at least" + CoreConstants.NEWLINE
+ + "one server is added to the storage cloud.");
+ return;
+ }
+
+ double totalDiskSpace = cluster.getTotalDiskSpace();
+ double diskSpaceInUse = cluster.getDiskSpaceInUse();
+ Double[] values = new Double[] { diskSpaceInUse / 1024, (totalDiskSpace - diskSpaceInUse) / 1024 };
+ createDiskSpaceChart(section, values);
+ }
+
+ private void createDiskSpaceChart(Composite section, Double[] values) {
+ String[] categories = new String[] { "Used Space (GB)", "Free Space (GB)" };
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
+
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 400;
+ data.heightHint = 180;
+ data.verticalAlignment = SWT.CENTER;
+ chartViewerComposite.setLayoutData(data);
+ }
+
+ private void createAlertsSection() {
+ alertsSection = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false);
+ populateAlerts();
+ }
+
+ private void populateAlerts() {
+ List<Alert> alerts = cluster.getAlerts();
+ for (Alert alert : alerts) {
+ addAlertLabel(alertsSection, alert);
+ }
+ alertsSection.layout();
+ form.reflow(true);
+ }
+
+ private void addAlertLabel(Composite section, Alert alert) {
+ CLabel lblAlert = new CLabel(section, SWT.FLAT);
+ GridData layoutData = new GridData();
+ layoutData.widthHint = 400;
+ layoutData.horizontalIndent = 20;
+ lblAlert.setLayoutData(layoutData);
+
+ Image alertImage = null;
+ switch (alert.getType()) {
+ case OFFLINE_VOLUME_BRICKS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.BRICK_OFFLINE_22x22);
+ break;
+ case DISK_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.LOW_DISK_SPACE_22x22);
+ break;
+ case OFFLINE_SERVERS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.SERVER_OFFLINE_22x22);
+ break;
+ case MEMORY_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.MEMORY_USAGE_ALERT_22x22);
+ break;
+ case CPU_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.SERVER_WARNING_22x22);
+ break;
+ case OFFLINE_VOLUME_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.VOLUME_OFFLINE_22x22);
+ break;
+ }
+ lblAlert.setText(alert.getMessage());
+ ControlDecoration dec = new ControlDecoration(lblAlert, SWT.LEFT);
+ dec.setImage(alertImage);
+ lblAlert.redraw();
+ }
+
+ private void createActionsSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Actions", null, 1, false);
+
+ ImageHyperlink imageHyperlink = toolkit.createImageHyperlink(section, SWT.NONE);
+ imageHyperlink.setText("Create Volume");
+ imageHyperlink.setImage(guiHelper.getImage(IImageKeys.CREATE_VOLUME_48x48));
+ imageHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ IHandlerService hs = (IHandlerService) getSite().getService(IHandlerService.class);
+ try {
+ hs.executeCommand(ActionConstants.COMMAND_CREATE_VOLUME, null);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ });
+
+ imageHyperlink = toolkit.createImageHyperlink(section, SWT.NONE);
+ imageHyperlink.setText("Add Server(s)");
+ imageHyperlink.setImage(guiHelper.getImage(IImageKeys.ADD_SERVER_48x48));
+ imageHyperlink.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ // Open the "discovered servers" view by selecting the corresponding entity in the navigation view
+ EntityGroup<Server> autoDiscoveredServersEntityGroup = GlusterDataModelManager.getInstance().getModel()
+ .getCluster().getEntityGroup(Server.class);
+
+ NavigationView navigationView = (NavigationView) guiHelper.getView(NavigationView.ID);
+ navigationView.selectEntity(autoDiscoveredServersEntityGroup);
+ }
+ });
+ }
+
+ private void createSections(Composite parent) {
+ form = guiHelper.setupForm(parent, toolkit, "Cluster Summary");
+
+ if (cluster.getServers().size() > 0
+ && (cluster.getAggregatedCpuStats().getRows() == null || cluster.getAggregatedNetworkStats().getRows() == null)) {
+ // cluster has servers, but stats are null. Happens when user logs in to a new cluster, '
+ // and then adds the first server.
+ GlusterDataModelManager.getInstance().initializeAggregatedCpuStats(cluster);
+ GlusterDataModelManager.getInstance().initializeAggregatedNetworkStats(cluster);
+ }
+
+ createServersSection();
+ createDiskSpaceSection();
+ createCPUUsageSection();
+ createNetworkUsageSection();
+ createActionsSection();
+ createAlertsSection();
+ createTasksSection();
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ private Composite createAreaChartSection(ServerStats stats, String sectionTitle, int dataColumnIndex, String unit, String timestampFormat, ChartPeriodLinkListener listener, double maxValue, int chartLinkColumnCount) {
+ Composite section = guiHelper.createSection(form, toolkit, sectionTitle, null, 1, false);
+ if (cluster.getServers().size() == 0) {
+ toolkit.createLabel(section, "This section will be populated after at least" + CoreConstants.NEWLINE
+ + "one server is added to the storage cloud.");
+ return section;
+ }
+
+ ChartUtil.getInstance().createAreaChart(toolkit, section, stats, dataColumnIndex, unit, timestampFormat, listener, maxValue, chartLinkColumnCount);
+ return section;
+ }
+
+ private void createCPUUsageSection() {
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_AGGREGATED_CHART_PERIOD);
+
+ // in case of CPU usage, there are three elements in usage data: user, system and total. we use total.
+ cpuChartSection = createAreaChartSection(cluster.getAggregatedCpuStats(), "CPU Usage (Aggregated)", 2, "%",
+ getTimestampFormatForPeriod(cpuStatsPeriod), chartUtil.new CpuChartPeriodLinkListener(null,
+ cpuStatsPeriod, toolkit), 100, 4);
+ }
+
+ private String getTimestampFormatForPeriod(String statsPeriod) {
+ if(statsPeriod.equals(GlusterConstants.STATS_PERIOD_1DAY)) {
+ return "HH:mm";
+ } else if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1WEEK)) {
+ return "dd-MMM HH:mm";
+ } else {
+ return "dd-MMM";
+ }
+ }
+
+ private void createNetworkUsageSection() {
+ IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+ String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_AGGREGATED_CHART_PERIOD);
+
+ // in case of network usage, there are three elements in usage data: received, transmitted and total. we use total.
+ networkChartSection = createAreaChartSection(cluster.getAggregatedNetworkStats(), "Network Usage (Aggregated)",
+ 2, "KiB/s", getTimestampFormatForPeriod(networkStatsPeriod),
+ chartUtil.new NetworkChartPeriodLinkListener(null, networkStatsPeriod, toolkit), -1, 4);
+ }
+
+ private void createTasksSection() {
+ tasksSection = guiHelper.createSection(form, toolkit, CoreConstants.RUNNING_TASKS, null, 1, false);
+ populateTasksSection();
+ }
+
+ private void populateTasksSection() {
+ for (TaskInfo taskInfo : cluster.getTaskInfoList()) {
+ if (taskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS) {
+ addTaskLabel(tasksSection, taskInfo);
+ }
+ }
+ tasksSection.layout();
+ form.reflow(true);
+ }
+
+ private void addTaskLabel(Composite section, TaskInfo taskInfo) {
+ //TODO: create link and open the task progress view
+ CLabel lblAlert = new CLabel(section, SWT.NONE);
+
+ Image taskImage = null;
+ switch(taskInfo.getType()) {
+ case DISK_FORMAT:
+ taskImage = guiHelper.getImage(IImageKeys.DISK_INITIALIZING_22x22);
+ break;
+ case BRICK_MIGRATE:
+ taskImage = guiHelper.getImage(IImageKeys.BRICK_MIGRATE_22x22);
+ break;
+ case VOLUME_REBALANCE:
+ taskImage = guiHelper.getImage(IImageKeys.VOLUME_REBALANCE_22x22);
+ break;
+ }
+
+ String description = taskInfo.getDescription();
+ switch (taskInfo.getStatus().getCode()) {
+ case Status.STATUS_CODE_PAUSE:
+ description += " (paused)";
+ break;
+ case Status.STATUS_CODE_COMMIT_PENDING:
+ description += " (commit pending)";
+ break;
+ case Status.STATUS_CODE_FAILURE:
+ description += " (failed)";
+ break;
+ }
+ lblAlert.setText(description);
+ lblAlert.setImage(taskImage);
+ lblAlert.redraw();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ if (form != null) {
+ form.setFocus();
+ }
+ }
+
+ private void refreshChartSection(Composite section, ServerStats stats, String statsPeriod, String unit,
+ double maxValue, int columnCount, ChartPeriodLinkListener linkListener, int dataColumnIndex) {
+ if(stats == null) {
+ return;
+ }
+
+ for (Control control : section.getChildren()) {
+ if (!control.isDisposed()) {
+ control.dispose();
+ }
+ }
+ chartUtil.createAreaChart(toolkit, section, stats, dataColumnIndex, unit,
+ getTimestampFormatForPeriod(statsPeriod), linkListener, maxValue, columnCount);
+ section.layout();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServerView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServerView.java
new file mode 100644
index 00000000..7ae6fe61
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServerView.java
@@ -0,0 +1,90 @@
+/**
+ * DiscoveredServerView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+/**
+ * @author root
+ *
+ */
+public class DiscoveredServerView extends ViewPart {
+ public static final String ID = DiscoveredServerView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private Server server;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ if (server == null) {
+ server = guiHelper.getSelectedEntity(getSite(), Server.class);
+ }
+ createSections(parent);
+ }
+
+ private void createServerSummarySection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Summary", null, 2, false);
+
+ toolkit.createLabel(section, "Number of CPUs: ", SWT.NONE);
+ toolkit.createLabel(section, "" + server.getNumOfCPUs(), SWT.NONE);
+
+ toolkit.createLabel(section, "Total Memory (GB): ", SWT.NONE);
+ toolkit.createLabel(section, "" + NumberUtil.formatNumber((server.getTotalMemory() / 1024)), SWT.NONE);
+
+ toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE);
+ toolkit.createLabel(section, "" + NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024)), SWT.NONE);
+ }
+
+ private void createSections(Composite parent) {
+ String serverName = server.getName();
+ form = guiHelper.setupForm(parent, toolkit, "Discovered Server Summary [" + serverName + "]");
+ createServerSummarySection();
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ if (form != null) {
+ form.setFocus();
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServersView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServersView.java
new file mode 100644
index 00000000..e3e7ec8a
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DiscoveredServersView.java
@@ -0,0 +1,83 @@
+/**
+ * DiscoveredServersView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.ServersPage;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Server;
+
+
+/**
+ *
+ */
+public class DiscoveredServersView extends ViewPart implements IDoubleClickListener {
+ public static final String ID = DiscoveredServersView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private EntityGroup<Server> servers;
+ private ServersPage page;
+
+ public DiscoveredServersView() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public void createPartControl(Composite parent) {
+ if (servers == null) {
+ Object selectedObj = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ if (selectedObj != null && ((EntityGroup) selectedObj).getEntityType() == Server.class) {
+ servers = (EntityGroup<Server>)selectedObj;
+ }
+ }
+
+ page = new ServersPage(parent, getSite(), servers);
+ page.addDoubleClickListener(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ NavigationView clusterView = (NavigationView) guiHelper.getView(NavigationView.ID);
+ if (clusterView != null) {
+ clusterView.selectEntity((Entity) ((StructuredSelection) event.getSelection()).getFirstElement());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DisksView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DisksView.java
new file mode 100644
index 00000000..1263a07f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/DisksView.java
@@ -0,0 +1,45 @@
+package org.gluster.storage.management.console.views;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.DisksPage;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class DisksView extends ViewPart {
+ public static final String ID = DisksView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private EntityGroup<GlusterServer> servers;
+ private DisksPage page;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void createPartControl(Composite parent) {
+ if (servers == null) {
+ servers = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ }
+
+ page = new DisksPage(parent, SWT.NONE, getSite(), getAllDisks(servers));
+ //page.layout(); // IMP: lays out the form properly
+ }
+
+ private List<Disk> getAllDisks(EntityGroup<GlusterServer> servers) {
+ List<Disk> disks = new ArrayList<Disk>();
+ for(GlusterServer server : servers.getEntities()) {
+ disks.addAll(server.getDisks());
+ }
+ return disks;
+ }
+
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerDisksView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerDisksView.java
new file mode 100644
index 00000000..8aa0fde1
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerDisksView.java
@@ -0,0 +1,84 @@
+/**
+ * GlusterServerDisksView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.ServerDisksPage;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Event.EVENT_TYPE;
+
+
+public class GlusterServerDisksView extends ViewPart {
+ public static final String ID = GlusterServerDisksView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private ClusterListener clusterListener;
+ private GlusterServer server;
+ private ServerDisksPage page;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ if (server == null) {
+ server = guiHelper.getSelectedEntity(getSite(), GlusterServer.class);
+ }
+ page = new ServerDisksPage(parent, SWT.NONE, getSite(), server.getDisks());
+
+ final ViewPart thisView = this;
+ clusterListener = new DefaultClusterListener() {
+ @Override
+ public void serverChanged(GlusterServer server, Event event) {
+ super.serverChanged(server, event);
+ if(event.getEventType() == EVENT_TYPE.GLUSTER_SERVER_CHANGED) {
+ if(!server.isOnline()) {
+ getViewSite().getPage().hideView(thisView);
+ }
+ }
+ }
+ };
+
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerLogsView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerLogsView.java
new file mode 100644
index 00000000..2e8ebe60
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerLogsView.java
@@ -0,0 +1,59 @@
+/**
+ * GlusterServerLogsView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.ServerLogsPage;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class GlusterServerLogsView extends ViewPart {
+ public static final String ID = GlusterServerLogsView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private GlusterServer server;
+ private ServerLogsPage page;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ if (server == null) {
+ server = guiHelper.getSelectedEntity(getSite(), GlusterServer.class);
+ }
+
+ page = new ServerLogsPage(parent, SWT.NONE, server);
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+}
+
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerSummaryView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerSummaryView.java
new file mode 100644
index 00000000..e5570ad9
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServerSummaryView.java
@@ -0,0 +1,544 @@
+/**
+ * GlusterServerSummaryView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.birt.chart.util.CDateTime;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.console.Activator;
+import org.gluster.storage.management.console.ConsoleConstants;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.NetworkInterfaceTableLabelProvider;
+import org.gluster.storage.management.console.preferences.PreferenceConstants;
+import org.gluster.storage.management.console.toolbar.GlusterToolbarManager;
+import org.gluster.storage.management.console.utils.ChartUtil;
+import org.gluster.storage.management.console.utils.ChartViewerComposite;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.console.utils.ChartUtil.ChartPeriodLinkListener;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.ServerStatsRow;
+import org.gluster.storage.management.core.model.Event.EVENT_TYPE;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+import com.ibm.icu.util.Calendar;
+import com.richclientgui.toolbox.gauges.CoolGauge;
+
+public class GlusterServerSummaryView extends ViewPart {
+ public static final String ID = GlusterServerSummaryView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private GlusterServer server;
+ private ClusterListener clusterListener;
+ private static final int CHART_WIDTH = 350;
+ private static final int CHART_HEIGHT = 250;
+ private static final GlusterLogger logger = GlusterLogger.getInstance();
+ private static final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
+
+ public enum NETWORK_INTERFACE_TABLE_COLUMN_INDICES {
+ INTERFACE, MODEL, SPEED, IP_ADDRESS, NETMASK, GATEWAY
+ };
+
+ private static final String[] NETWORK_INTERFACE_TABLE_COLUMN_NAMES = { "Interface", "Model", "Speed", "IP Address",
+ "Netmask", "Gateway" };
+ private CoolGauge cpuGauge;
+ private IPropertyChangeListener propertyChangeListener;
+ private Composite cpuUsageSection;
+ private Composite networkUsageSection;
+ private Composite memoryUsageSection;
+ private static final ChartUtil chartUtil = ChartUtil.getInstance();
+ private Composite serverSummarySection;
+ private Label numCpus;
+ private ProgressBar memoryUsageBar;
+ private ProgressBar diskUsageBar;
+ private CLabel lblServerStatus;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (server == null) {
+ server = guiHelper.getSelectedEntity(getSite(), GlusterServer.class);
+ }
+ setPartName("Summary");
+ createSections(parent);
+
+ createListeners();
+ }
+
+ private void createListeners() {
+ // Refresh the server details whenever the server has changed
+ createClusterListener();
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ createPropertyChangeListener();
+ preferenceStore.addPropertyChangeListener(propertyChangeListener);
+ }
+
+ private void createPropertyChangeListener() {
+ propertyChangeListener = new IPropertyChangeListener() {
+
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ String propertyName = event.getProperty();
+ if(propertyName.equals(PreferenceConstants.P_CPU_CHART_PERIOD)) {
+ refreshCpuChart();
+ } else if(propertyName.equals(PreferenceConstants.P_MEM_CHART_PERIOD)) {
+ refreshMemoryChart();
+ } else if (propertyName.equals(PreferenceConstants.P_NETWORK_CHART_PERIOD)
+ || propertyName.equals(PreferenceConstants.P_DEFAULT_NETWORK_INTERFACE_PFX + server.getName())) {
+ refreshNetworkChart();
+ }
+ }
+ };
+ }
+
+ private void createClusterListener() {
+ final GlusterToolbarManager toolbarManager = new GlusterToolbarManager(getSite().getWorkbenchWindow());
+ final GlusterServer thisServer = server;
+ clusterListener = new DefaultClusterListener() {
+
+ @Override
+ public void serverChanged(GlusterServer server, Event event) {
+ if (event.getEventType() == EVENT_TYPE.GLUSTER_SERVER_CHANGED && server == thisServer) {
+ updateServerDetails();
+ toolbarManager.updateToolbar(server);
+ refreshCharts();
+ }
+ }
+ };
+ }
+
+ private void refreshCharts() {
+ refreshCpuChart();
+ refreshMemoryChart();
+ refreshNetworkChart();
+ }
+
+ private void refreshNetworkChart() {
+ guiHelper.clearSection(networkUsageSection);
+ String statsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_CHART_PERIOD);
+ String networkInterface = preferenceStore.getString(PreferenceConstants.P_DEFAULT_NETWORK_INTERFACE_PFX + server.getName());
+ if(networkInterface == null || networkInterface.isEmpty()) {
+ networkInterface = server.getNetworkInterfaces().get(0).getName();
+ }
+ ServerStats stats = new GlusterServersClient().getNetworkStats(server.getName(), networkInterface, statsPeriod);
+ chartUtil.refreshChartSection(toolkit, networkUsageSection, stats, statsPeriod, "KiB/s", -1, 5, chartUtil.new NetworkChartPeriodLinkListener(server, statsPeriod, toolkit), 2);
+ }
+
+ private void refreshMemoryChart() {
+ guiHelper.clearSection(memoryUsageSection);
+ String statsPeriod = preferenceStore.getString(PreferenceConstants.P_MEM_CHART_PERIOD);
+ ServerStats stats = new GlusterServersClient().getMemoryStats(server.getName(), statsPeriod);
+ chartUtil.refreshChartSection(toolkit, memoryUsageSection, stats, statsPeriod, "%", 100, 4, chartUtil.new MemoryChartPeriodLinkListener(server.getName(), statsPeriod, toolkit), 0);
+ }
+
+ private void refreshCpuChart() {
+ guiHelper.clearSection(cpuUsageSection);
+ String statsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_CHART_PERIOD);
+ ServerStats stats = new GlusterServersClient().getCpuStats(server.getName(), statsPeriod);
+ chartUtil.refreshChartSection(toolkit, cpuUsageSection, stats, statsPeriod, "%", 100, 4,
+ chartUtil.new CpuChartPeriodLinkListener(server.getName(), statsPeriod, toolkit), 2);
+ }
+
+ private void updateServerDetails() {
+ // TODO: Update the server details (cpu usage, memory usage)
+ populateServerSummarySection(server);
+
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ preferenceStore.removePropertyChangeListener(propertyChangeListener);
+ }
+
+ private void createAreaChart(Composite section, Calendar timestamps[], Double values[], String unit) {
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values, unit, "HH:mm", 100);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = CHART_WIDTH;
+ data.heightHint = CHART_HEIGHT;
+ chartViewerComposite.setLayoutData(data);
+ }
+
+ private void extractChartData(ServerStats stats, List<Calendar> timestamps, List<Double> data, int dataColumnIndex) {
+ for(ServerStatsRow row : stats.getRows()) {
+ Double cpuUsage = row.getUsageData().get(dataColumnIndex);
+ if(!cpuUsage.isNaN()) {
+ timestamps.add(new CDateTime(row.getTimestamp() * 1000));
+ data.add(cpuUsage);
+ }
+ }
+ }
+
+ private void createAreaChartSection(ServerStats stats, String sectionTitle, int dataColumnIndex, String unit) {
+ List<Calendar> timestamps = new ArrayList<Calendar>();
+ List<Double> data = new ArrayList<Double>();
+ extractChartData(stats, timestamps, data, dataColumnIndex);
+
+ if(timestamps.size() == 0) {
+ // Log a message saying no CPU stats available
+ return;
+ }
+
+ Composite section = guiHelper.createSection(form, toolkit, sectionTitle, null, 1, false);
+ createAreaChart(section, timestamps.toArray(new Calendar[0]), data.toArray(new Double[0]), unit);
+
+// 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) };
+//
+// 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, "%");
+ createChartLinks(section, 4);
+ }
+
+ private void createMemoryUsageSection() {
+ String memStatsPeriod = preferenceStore.getString(PreferenceConstants.P_MEM_CHART_PERIOD);
+ memoryUsageSection = guiHelper.createSection(form, toolkit, "Memory Usage", null, 1, false);
+
+ ServerStats stats;
+ try {
+ stats = new GlusterServersClient().getMemoryStats(server.getName(), memStatsPeriod);
+ } catch(Exception e) {
+ logger.error("Couldn't fetch memory usage statistics for server [" + server.getName() + "]", e);
+ toolkit.createLabel(memoryUsageSection, "Couldn't fetch memory usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]");
+ return;
+ }
+
+ // in case of memory usage, there are four elements in usage data: user, free, cache, buffer and total. we use "user".
+ ChartUtil chartUtil = ChartUtil.getInstance();
+ chartUtil.createAreaChart(toolkit, memoryUsageSection, stats, 0, "%", chartUtil
+ .getTimestampFormatForPeriod(memStatsPeriod),
+ chartUtil.new MemoryChartPeriodLinkListener(server.getName(), memStatsPeriod, toolkit), 100, 4);
+ }
+
+ private void createCPUUsageSection() {
+ String cpuStatsPeriod = preferenceStore.getString(PreferenceConstants.P_CPU_CHART_PERIOD);
+ cpuUsageSection = guiHelper.createSection(form, toolkit, "CPU Usage", null, 1, false);
+
+ ServerStats stats;
+ try {
+ stats = new GlusterServersClient().getCpuStats(server.getName(), cpuStatsPeriod);
+ } catch(Exception e) {
+ logger.error("Couldn't fetch CPU usage statistics for server [" + server.getName() + "]", e);
+ toolkit.createLabel(cpuUsageSection, "Couldn't fetch CPU usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]");
+ return;
+ }
+
+ // in case of CPU usage, there are three elements in usage data: user, system and total. we use total.
+ chartUtil.createAreaChart(toolkit, cpuUsageSection, stats, 2, "%", chartUtil
+ .getTimestampFormatForPeriod(cpuStatsPeriod),
+ chartUtil.new CpuChartPeriodLinkListener(server.getName(), cpuStatsPeriod, toolkit), 100, 4);
+ }
+
+ private void createNetworkUsageSection() {
+ final String networkStatsPeriod = preferenceStore.getString(PreferenceConstants.P_NETWORK_CHART_PERIOD);
+ networkUsageSection = guiHelper.createSection(form, toolkit, "Network Usage", null, 1, false);
+
+ String networkInterface = server.getNetworkInterfaces().get(0).getName();
+ ServerStats stats;
+ try {
+ stats = new GlusterServersClient().getNetworkStats(server.getName(), networkInterface, networkStatsPeriod);
+ } catch(Exception e) {
+ logger.error("Couldn't fetch Network usage statistics for server [" + server.getName() + "] network interface [" + networkInterface + "]", e);
+ toolkit.createLabel(networkUsageSection, "Couldn't fetch CPU usage statistics for server [" + server.getName() + "]! Error: [" + e.getMessage() + "]");
+ return;
+ }
+
+ // in case of network usage, there are three elements in usage data: received, transmitted and total. we use total.
+ final ChartUtil chartUtil = ChartUtil.getInstance();
+ final ChartPeriodLinkListener networkChartPeriodLinkListener = chartUtil.new NetworkChartPeriodLinkListener(server, networkStatsPeriod, toolkit);
+ chartUtil.createAreaChart(toolkit, networkUsageSection, stats, 2, "KiB/s", chartUtil
+ .getTimestampFormatForPeriod(networkStatsPeriod),
+ networkChartPeriodLinkListener , -1, 5);
+ }
+
+ private Composite createChartLinks(Composite section, int columnCount) {
+ GridLayout layout = new org.eclipse.swt.layout.GridLayout(columnCount, false);
+ layout.marginBottom = 0;
+ layout.marginTop = 0;
+ layout.marginLeft = (CHART_WIDTH - (50*columnCount)) / 2;
+ Composite graphComposite = toolkit.createComposite(section, SWT.NONE);
+ graphComposite.setLayout(layout);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = CHART_WIDTH;
+ graphComposite.setLayoutData(data);
+
+ Label label1 = toolkit.createLabel(graphComposite, "1 day");
+ Hyperlink link1 = toolkit.createHyperlink(graphComposite, "1 week", SWT.NONE);
+ Hyperlink link2 = toolkit.createHyperlink(graphComposite, "1 month", SWT.NONE);
+ Hyperlink link3 = toolkit.createHyperlink(graphComposite, "1 year", SWT.NONE);
+
+ return graphComposite;
+ }
+
+ 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) {
+ try {
+ new ProgressMonitorDialog(getSite().getShell()).run(false, false, new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ monitor.beginTask("Creating Server Summary View", 4);
+ monitor.setTaskName("Creating Memory Usage Section");
+ createMemoryUsageSection();
+ monitor.worked(1);
+
+ monitor.setTaskName("Creating Network Usage Section");
+ createNetworkUsageSection();
+ monitor.worked(1);
+
+ monitor.setTaskName("Creating CPU Usage Section");
+ createCPUUsageSection();
+ monitor.worked(1);
+
+ monitor.setTaskName("Creating Network Interfaces Section");
+ createNetworkInterfacesSection(server, toolkit, form);
+ monitor.worked(1);
+ monitor.done();
+ }
+ });
+ } catch (Exception e) {
+ String errMsg = "Exception while creating the Gluster Server Summary View : [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ MessageDialog.openError(getSite().getShell(), ConsoleConstants.CONSOLE_TITLE, errMsg);
+ }
+ }
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ private void createServerSummarySection(GlusterServer server, FormToolkit toolkit, final ScrolledForm form) {
+ serverSummarySection = guiHelper.createSection(form, toolkit, "Summary", null, 2, false);
+ // toolkit.createLabel(section, "Preferred Network: ", SWT.NONE);
+ // toolkit.createLabel(section, server.getPreferredNetworkInterface().getName(), SWT.NONE);
+
+ if (server.isOnline()) {
+ toolkit.createLabel(serverSummarySection, "Number of CPUs: ", SWT.NONE);
+ numCpus = toolkit.createLabel(serverSummarySection, "" + server.getNumOfCPUs(), SWT.NONE);
+
+ toolkit.createLabel(serverSummarySection, "% CPU Usage (avg): ", SWT.NONE);
+ cpuGauge = new CoolGauge(serverSummarySection, guiHelper.getImage(IImageKeys.GAUGE_SMALL));
+
+ toolkit.createLabel(serverSummarySection, "Memory Usage: ", SWT.NONE);
+ memoryUsageBar = new ProgressBar(serverSummarySection, SWT.SMOOTH);
+
+ // toolkit.createLabel(section, "Memory Usage: ", SWT.NONE);
+ // final CoolProgressBar bar = new CoolProgressBar(section,SWT.HORIZONTAL,
+ // guiHelper.getImage(IImageKeys.PROGRESS_BAR_LEFT),
+ // guiHelper.getImage(IImageKeys.PROGRESS_BAR_FILLED),
+ // guiHelper.getImage(IImageKeys.PROGRESS_BAR_EMPTY),
+ // guiHelper.getImage(IImageKeys.PROGRESS_BAR_RIGHT));
+ // bar.updateProgress(server.getMemoryInUse() / server.getTotalMemory());
+
+ // toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE);
+ // toolkit.createLabel(section, online ? "" + server.getTotalDiskSpace() : "NA", SWT.NONE);
+ //
+ // toolkit.createLabel(section, "Disk Space in Use (GB): ", SWT.NONE);
+ // toolkit.createLabel(section, online ? "" + server.getDiskSpaceInUse() : "NA", SWT.NONE);
+
+ toolkit.createLabel(serverSummarySection, "Disk Usage: ", SWT.NONE);
+ diskUsageBar = new ProgressBar(serverSummarySection, SWT.SMOOTH);
+ }
+
+ toolkit.createLabel(serverSummarySection, "Status: ", SWT.NONE);
+ lblServerStatus = new CLabel(serverSummarySection, SWT.NONE);
+ populateServerSummarySection(server);
+ }
+
+ private void populateServerSummarySection(GlusterServer server) {
+ if (server.isOnline()) {
+ numCpus.setText("" + server.getNumOfCPUs());
+ numCpus.redraw();
+
+ cpuGauge.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
+ cpuGauge.setGaugeNeedleColour(Display.getDefault().getSystemColor(SWT.COLOR_RED));
+ cpuGauge.setGaugeNeedleWidth(2);
+ cpuGauge.setGaugeNeedlePivot(new Point(66, 65));
+
+ cpuGauge.setPoints(getPnts());
+ cpuGauge.setLevel(server.getCpuUsage() / 100);
+ cpuGauge.setToolTipText(server.getCpuUsage() + "%");
+ cpuGauge.redraw();
+
+ memoryUsageBar.setMinimum(0);
+ memoryUsageBar.setMaximum((int) Math.round(server.getTotalMemory()));
+ memoryUsageBar.setSelection((int) Math.round(server.getMemoryInUse()));
+ memoryUsageBar.setToolTipText("Total: " + NumberUtil.formatNumber((server.getTotalMemory() / 1024))
+ + "GB, In Use: " + NumberUtil.formatNumber((server.getMemoryInUse() / 1024)) + "GB");
+
+ diskUsageBar.setMinimum(0);
+ diskUsageBar.setMaximum((int) Math.round(server.getTotalDiskSpace()));
+ diskUsageBar.setSelection((int) Math.round(server.getDiskSpaceInUse()));
+ diskUsageBar.setToolTipText("Total: " + NumberUtil.formatNumber((server.getTotalDiskSpace() / 1024))
+ + "GB, In Use: " + NumberUtil.formatNumber((server.getDiskSpaceInUse() / 1024)) + "GB");
+
+ }
+ lblServerStatus.setText(server.getStatusStr());
+ lblServerStatus.setImage(server.getStatus() == GlusterServer.SERVER_STATUS.ONLINE ? guiHelper
+ .getImage(IImageKeys.STATUS_ONLINE_16x16) : guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16));
+ toolkit.adapt(lblServerStatus, true, true);
+
+ serverSummarySection.layout();
+ form.reflow(true);
+ }
+
+ private List<Point> getPnts() {
+ final List<Point> pnts = new ArrayList<Point>();
+ pnts.add(new Point(47, 98));
+ pnts.add(new Point(34, 84));
+ pnts.add(new Point(29, 65));
+ pnts.add(new Point(33, 48));
+ pnts.add(new Point(48, 33));
+ pnts.add(new Point(66, 28));
+ pnts.add(new Point(83, 32));
+ pnts.add(new Point(98, 47));
+ pnts.add(new Point(103, 65));
+ pnts.add(new Point(98, 83));
+ pnts.add(new Point(84, 98));
+ return pnts;
+ }
+
+ private Composite createNetworkInterfacesSection(GlusterServer server, FormToolkit toolkit, ScrolledForm form) {
+ final Composite section = guiHelper.createSection(form, toolkit, "Network Interfaces", null, 1, false);
+ createNetworkInterfacesTableViewer(createTableViewerComposite(section), server);
+ // Hyperlink changePreferredNetworkLink = toolkit.createHyperlink(section, "Change Preferred Network",
+ // SWT.NONE);
+ // changePreferredNetworkLink.addHyperlinkListener(new HyperlinkAdapter() {
+ //
+ // @Override
+ // public void linkActivated(HyperlinkEvent e) {
+ // new MessageDialog(
+ // section.getShell(),
+ // "Gluster Storage Platform",
+ // guiHelper.getImage(IImageKeys.SERVER),
+ // "This will show additional controls to help user choose a new network interface. TO BE IMPLEMENTED.",
+ // MessageDialog.INFORMATION, new String[] { "OK" }, 0).open();
+ // }
+ // });
+ return section;
+ }
+
+ private TableViewer createNetworkInterfacesTableViewer(final Composite parent, GlusterServer server) {
+ TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI);
+ // TableViewer tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI);
+ tableViewer.setLabelProvider(new NetworkInterfaceTableLabelProvider());
+ tableViewer.setContentProvider(new ArrayContentProvider());
+
+ setupNetworkInterfaceTable(parent, tableViewer.getTable());
+ tableViewer.setInput(server.getNetworkInterfaces().toArray());
+
+ return tableViewer;
+ }
+
+ private void setupNetworkInterfaceTable(Composite parent, Table table) {
+ table.setHeaderVisible(true);
+ table.setLinesVisible(false);
+
+ TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table,
+ NETWORK_INTERFACE_TABLE_COLUMN_NAMES);
+ parent.setLayout(tableColumnLayout);
+
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.INTERFACE, SWT.CENTER, 70);
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.MODEL, SWT.CENTER, 70);
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.SPEED, SWT.CENTER, 70);
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.IP_ADDRESS, SWT.CENTER, 100);
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.NETMASK, SWT.CENTER, 70);
+ setColumnProperties(table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES.GATEWAY, SWT.CENTER, 70);
+ }
+
+ private Composite createTableViewerComposite(Composite parent) {
+ Composite tableViewerComposite = new Composite(parent, SWT.NO);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ GridData tableLayoutData = new GridData(SWT.FILL, SWT.FILL, true, false);
+ tableLayoutData.widthHint = 400;
+ tableLayoutData.minimumWidth = 400;
+ // tableLayoutData.grabExcessHorizontalSpace = true;
+ tableViewerComposite.setLayoutData(tableLayoutData);
+ return tableViewerComposite;
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ public void setColumnProperties(Table table, NETWORK_INTERFACE_TABLE_COLUMN_INDICES columnIndex, int alignment,
+ int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ @Override
+ public void setFocus() {
+ form.setFocus();
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersSummaryView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersSummaryView.java
new file mode 100644
index 00000000..c7435166
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersSummaryView.java
@@ -0,0 +1,290 @@
+/**
+ * GlusterServersSummaryView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.ChartViewerComposite;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Alert.ALERT_TYPES;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+
+
+/**
+ *
+ */
+public class GlusterServersSummaryView extends ViewPart {
+ public static final String ID = GlusterServersSummaryView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private ClusterListener clusterListener;
+ private EntityGroup<GlusterServer> servers;
+ private Composite alertsSection;
+ private Composite serversAvailabilitySection;
+ private Composite tasksSection;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void createPartControl(Composite parent) {
+ if (servers == null) {
+ servers = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ }
+ setPartName("Summary");
+ createSections(parent);
+
+ clusterListener = new DefaultClusterListener() {
+ @Override
+ public void serverAdded(GlusterServer server) {
+ super.serverAdded(server);
+ updateServerAvailabilitySection();
+ }
+
+ @Override
+ public void serverRemoved(GlusterServer server) {
+ super.serverRemoved(server);
+ updateServerAvailabilitySection();
+ }
+
+ @Override
+ public void serverChanged(GlusterServer server, Event event) {
+ super.serverChanged(server, event);
+ updateServerAvailabilitySection();
+ }
+
+ private void updateServerAvailabilitySection() {
+ guiHelper.clearSection(serversAvailabilitySection);
+ populateAvailabilitySection();
+ }
+
+ @Override
+ public void alertsGenerated() {
+ super.alertsGenerated();
+ guiHelper.clearSection(alertsSection);
+ populateAlertSection();
+ }
+
+ @Override
+ public void taskAdded(TaskInfo taskInfo) {
+ super.taskAdded(taskInfo);
+ updateTasksSection();
+ }
+
+ @Override
+ public void taskRemoved(TaskInfo taskInfo) {
+ super.taskRemoved(taskInfo);
+ updateTasksSection();
+ }
+
+ @Override
+ public void taskUpdated(TaskInfo taskInfo) {
+ super.taskUpdated(taskInfo);
+ updateTasksSection();
+ }
+
+ private void updateTasksSection() {
+ guiHelper.clearSection(tasksSection);
+ populateTasksSection();
+ }
+ };
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+
+ /**
+ * @param parent
+ */
+ private void createSections(Composite parent) {
+ form = guiHelper.setupForm(parent, toolkit, "Servers - Summary");
+
+ createSummarySection();
+ createRunningTasksSection();
+ createAlertsSection();
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ private void createSummarySection() {
+ serversAvailabilitySection = guiHelper.createSection(form, toolkit, "Availability", null, 2, false);
+ populateAvailabilitySection();
+ }
+
+ private void populateAvailabilitySection() {
+ if (servers.getEntities().size() == 0) {
+ toolkit.createLabel(serversAvailabilitySection, "This section will be populated after at least"
+ + CoreConstants.NEWLINE + "one server is added to the storage cloud.");
+ return;
+ }
+
+ Double[] values = new Double[] { Double.valueOf(getServerCountByStatus(servers, SERVER_STATUS.ONLINE)),
+ Double.valueOf(getServerCountByStatus(servers, SERVER_STATUS.OFFLINE)) };
+ createStatusChart(serversAvailabilitySection, values);
+ }
+
+ private int getServerCountByStatus(EntityGroup<GlusterServer> servers, SERVER_STATUS status) {
+ int count = 0;
+ for (GlusterServer server : servers.getEntities()) {
+ if (server.getStatus() == status) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private void createStatusChart(Composite section, Double[] values) {
+ String[] categories = new String[] { "Online", "Offline" };
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
+
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 300;
+ data.heightHint = 150;
+ chartViewerComposite.setLayoutData(data);
+ }
+
+ private void createAlertsSection() {
+ alertsSection = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false);
+ populateAlertSection();
+ }
+
+ private void populateAlertSection() {
+ List<Alert> alerts = GlusterDataModelManager.getInstance().getModel().getCluster().getAlerts();
+
+ for (Alert alert : alerts) {
+ if (alert.getType() == ALERT_TYPES.DISK_USAGE_ALERT || alert.getType() != ALERT_TYPES.OFFLINE_SERVERS_ALERT
+ || alert.getType() == ALERT_TYPES.MEMORY_USAGE_ALERT
+ || alert.getType() == ALERT_TYPES.CPU_USAGE_ALERT) {
+ addAlertLabel(alertsSection, alert);
+ }
+ }
+ alertsSection.pack(true);
+ form.reflow(true);
+ }
+
+ private void addAlertLabel(Composite section, Alert alert) {
+ CLabel lblAlert = new CLabel(section, SWT.FLAT);
+ Image alertImage = null;
+ switch (alert.getType()) {
+ case DISK_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.LOW_DISK_SPACE_22x22);
+ break;
+ case OFFLINE_SERVERS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.SERVER_OFFLINE_22x22);
+ break;
+ case MEMORY_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.MEMORY_USAGE_ALERT_22x22);
+ break;
+ case CPU_USAGE_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.SERVER_WARNING_22x22);
+ break;
+ }
+ lblAlert.setImage(alertImage);
+ lblAlert.setText(alert.getMessage());
+ lblAlert.redraw();
+ }
+
+ private void createRunningTasksSection() {
+ tasksSection = guiHelper.createSection(form, toolkit, CoreConstants.RUNNING_TASKS, null, 1, false);
+ populateTasksSection();
+ }
+
+ private void populateTasksSection() {
+ for (TaskInfo taskInfo : GlusterDataModelManager.getInstance().getModel().getCluster().getTaskInfoList()) {
+ // Exclude volume related tasks
+ if (taskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS
+ && taskInfo.getType() != TASK_TYPE.VOLUME_REBALANCE
+ && taskInfo.getType() != TASK_TYPE.BRICK_MIGRATE) {
+ addTaskLabel(tasksSection, taskInfo);
+ }
+ }
+ tasksSection.layout();
+ form.reflow(true);
+ }
+
+ private void addTaskLabel(Composite section, TaskInfo taskInfo) {
+ CLabel lblTask = new CLabel(section, SWT.NONE);
+ Image taskImage = null;
+ switch(taskInfo.getType()) {
+ case DISK_FORMAT:
+ taskImage = guiHelper.getImage(IImageKeys.DISK_INITIALIZING_22x22);
+ break;
+ case BRICK_MIGRATE:
+ taskImage = guiHelper.getImage(IImageKeys.BRICK_MIGRATE_22x22);
+ break;
+ case VOLUME_REBALANCE:
+ taskImage = guiHelper.getImage(IImageKeys.VOLUME_REBALANCE_22x22);
+ break;
+ }
+
+ String description = taskInfo.getDescription();
+ switch (taskInfo.getStatus().getCode()) {
+ case Status.STATUS_CODE_PAUSE:
+ description += " (paused)";
+ break;
+ case Status.STATUS_CODE_COMMIT_PENDING:
+ description += " (commit pending)";
+ break;
+ case Status.STATUS_CODE_FAILURE:
+ description += " (failed)";
+ break;
+ }
+
+ lblTask.setText(description);
+ lblTask.setImage(taskImage);
+ lblTask.redraw();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ form.setFocus();
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersView.java
new file mode 100644
index 00000000..fe4e3bb3
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterServersView.java
@@ -0,0 +1,78 @@
+/**
+ * GlusterServersView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.GlusterServersPage;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+/**
+ * @author root
+ *
+ */
+public class GlusterServersView extends ViewPart implements IDoubleClickListener {
+ public static final String ID = GlusterServersView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private EntityGroup<GlusterServer> servers;
+ private GlusterServersPage page;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void createPartControl(Composite parent) {
+ if (servers == null) {
+ servers = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ }
+
+ page = new GlusterServersPage(getSite(), parent, SWT.NONE, servers);
+ page.addDoubleClickListener(this);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
+ */
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ NavigationView clusterView = (NavigationView) guiHelper.getView(NavigationView.ID);
+ if (clusterView != null) {
+ clusterView.selectEntity((Entity) ((StructuredSelection) event.getSelection()).getFirstElement());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterViewsManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterViewsManager.java
new file mode 100644
index 00000000..a4d0a98f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/GlusterViewsManager.java
@@ -0,0 +1,130 @@
+/**
+ * GlusterViewsManager.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.gluster.storage.management.console.ConsoleConstants;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Volume;
+
+
+/**
+ * @see ViewsManager
+ */
+public class GlusterViewsManager implements ViewsManager {
+ private IWorkbenchPage page;
+
+ public GlusterViewsManager(IWorkbenchPage page) {
+ this.page = page;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.ViewsManager#updateViews(org.gluster.storage.management.core.model.Entity)
+ */
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void updateViews(Entity entity) {
+ closeAllViews();
+
+ try {
+ if (entity instanceof EntityGroup) {
+ showViewsForEntityGroup((EntityGroup)entity);
+ } else if (entity.getClass() == Server.class) {
+ showViewsForDiscoveredServer((Server)entity);
+ } else if (entity.getClass() == GlusterServer.class) {
+ showViewsForGlusterServer((GlusterServer)entity);
+ } else if (entity instanceof Volume) {
+ showViewsForVolume((Volume)entity);
+ } else if (entity instanceof Cluster) {
+ showViewsForCluster((Cluster)entity);
+ }
+ } catch (PartInitException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void closeAllViews() {
+ IViewReference[] viewReferences = page.getViewReferences();
+ for (final IViewReference viewReference : viewReferences) {
+ if (!(viewReference.getId().equals(NavigationView.ID) || viewReference.getId().equals(
+ ConsoleConstants.TERMINAL_VIEW_ID))) {
+ page.hideView(viewReference);
+ }
+ }
+ }
+
+ private void showViewsForCluster(Cluster cluster) throws PartInitException {
+ page.showView(ClusterSummaryView.ID);
+ page.showView(TasksView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ }
+
+ private void showViewsForVolume(Volume volume) throws PartInitException {
+ page.showView(VolumeSummaryView.ID);
+ page.showView(VolumeBricksView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ page.showView(VolumeOptionsView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ page.showView(VolumeLogsView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ }
+
+ private void showViewsForGlusterServer(GlusterServer server) throws PartInitException {
+ page.showView(GlusterServerSummaryView.ID);
+ if (server.getStatus() == GlusterServer.SERVER_STATUS.ONLINE) {
+ page.showView(GlusterServerDisksView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ //page.showView(GlusterServerLogsView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ }
+ }
+
+ private void showViewsForDiscoveredServer(Server server) throws PartInitException {
+ page.showView(DiscoveredServerView.ID);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private void showViewsForEntityGroup(EntityGroup entityGroup) throws PartInitException {
+ Class entityType = entityGroup.getEntityType();
+ if (entityType == Server.class) {
+ showViewForServers(entityGroup);
+ } else if (entityType == Volume.class) {
+ showViewsForVolumes(entityGroup);
+ } else if (entityType == GlusterServer.class) {
+ showViewsForGlusterServers(entityGroup);
+ }
+ }
+
+ private void showViewsForGlusterServers(EntityGroup<GlusterServer> server) throws PartInitException {
+ page.showView(GlusterServersSummaryView.ID);
+ page.showView(GlusterServersView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ page.showView(DisksView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ }
+
+ private void showViewsForVolumes(EntityGroup<Volume> volumes) throws PartInitException {
+ page.showView(VolumesSummaryView.ID);
+ page.showView(VolumesView.ID, null, IWorkbenchPage.VIEW_CREATE);
+ }
+
+ private void showViewForServers(EntityGroup<Server> servers) throws PartInitException {
+ page.showView(DiscoveredServersView.ID);
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationTreeLabelDecorator.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationTreeLabelDecorator.java
new file mode 100644
index 00000000..45f7119f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationTreeLabelDecorator.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.gluster.storage.management.console.Application;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class NavigationTreeLabelDecorator implements ILightweightLabelDecorator {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void decorate(Object element, IDecoration decoration) {
+ if (element instanceof Volume) {
+ Volume volume = (Volume) element;
+ if (volume.getStatus() == Volume.VOLUME_STATUS.OFFLINE) {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_OFFLINE_8x8));
+ } else {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_ONLINE_8x8));
+ }
+ }
+
+ if (element instanceof GlusterServer) {
+ GlusterServer server = (GlusterServer) element;
+ if (server.getStatus() == GlusterServer.SERVER_STATUS.OFFLINE) {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_OFFLINE_8x8));
+ } else {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_ONLINE_8x8));
+ }
+ }
+
+ if (element instanceof Server) {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_STAR_8x8));
+ }
+
+ if(element instanceof EntityGroup && ((EntityGroup)element).getEntityType() == Server.class) {
+ decoration.addOverlay(AbstractUIPlugin.imageDescriptorFromPlugin(Application.PLUGIN_ID,
+ IImageKeys.OVERLAY_STAR_8x8));
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationView.java
new file mode 100644
index 00000000..0c565a24
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/NavigationView.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.toolbar.GlusterToolbarManager;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterDataModel;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class NavigationView extends ViewPart implements ISelectionListener {
+ public static final String ID = NavigationView.class.getName();
+ private TreeViewer treeViewer;
+ private IAdapterFactory adapterFactory = new ClusterAdapterFactory();
+ private GlusterToolbarManager toolbarManager;
+ private Entity entity;
+ private GlusterViewsManager viewsManager;
+ private DefaultClusterListener clusterListener;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ createNavigationTree(parent);
+
+ // Create the views and toolbar managers
+ toolbarManager = new GlusterToolbarManager(getSite().getWorkbenchWindow());
+ viewsManager = new GlusterViewsManager(getSite().getPage());
+
+ // listen to selection events to update views/toolbar accordingly
+ getSite().getPage().addSelectionListener(this);
+ }
+
+ private void createNavigationTree(Composite parent) {
+ GlusterDataModel model = GlusterDataModelManager.getInstance().getModel();
+
+ Platform.getAdapterManager().registerAdapters(adapterFactory, Entity.class);
+ treeViewer = new TreeViewer(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
+ treeViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
+ treeViewer.setContentProvider(new BaseWorkbenchContentProvider());
+ treeViewer.setInput(model);
+ treeViewer.expandAll();
+ // select the first element by default
+ treeViewer.setSelection(new StructuredSelection(model.getChildren().get(0)));
+
+ setupContextMenu();
+
+ // register as selection provider so that other views can listen to any selection events on the tree
+ getSite().setSelectionProvider(treeViewer);
+
+ clusterListener = new DefaultClusterListener() {
+ public void modelChanged() {
+ treeViewer.refresh(true);
+ }
+
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ super.volumeChanged(volume, event);
+ treeViewer.update(volume, null);
+ if (volume == entity) {
+ // this makes sure that the toolbar buttons get updated according to new status
+ selectEntity(volume);
+ }
+ }
+
+ @Override
+ public void volumeDeleted(Volume volume) {
+ super.volumeDeleted(volume);
+ if(volume == entity) {
+ // volume selected was deleted. select the root element in the tree.
+ selectEntity(GlusterDataModelManager.getInstance().getModel().getCluster());
+ }
+ }
+
+ @Override
+ public void serverRemoved(GlusterServer server) {
+ super.serverRemoved(server);
+ if(server == entity) {
+ // server selected was removed. select the root element in the tree.
+ selectEntity(GlusterDataModelManager.getInstance().getModel().getCluster());
+ }
+ };
+ };
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+ }
+
+ private void setupContextMenu() {
+ MenuManager menuManager = new MenuManager("&Gluster", "gluster.context.menu");
+ Menu contextMenu = menuManager.createContextMenu(treeViewer.getControl());
+ treeViewer.getTree().setMenu(contextMenu);
+ getSite().registerContextMenu(menuManager, treeViewer);
+ }
+
+ public void selectEntity(Entity entity) {
+ treeViewer.setSelection(new StructuredSelection(entity));
+ treeViewer.reveal(entity);
+ setFocus(); // this ensures that the "selection changed" event gets fired
+ }
+
+ @Override
+ public void setFocus() {
+ treeViewer.getControl().setFocus();
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (part instanceof NavigationView && selection instanceof TreeSelection) {
+ Entity selectedEntity = (Entity) ((TreeSelection) selection).getFirstElement();
+
+ if (selectedEntity != null && selectedEntity != entity) {
+ entity = selectedEntity;
+
+ // update views and toolbar buttons visibility based on selected entity
+ viewsManager.updateViews(entity);
+ toolbarManager.updateToolbar(entity);
+
+ // Opening of other views may cause navigation tree to lose focus; get it back.
+ setFocus();
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/TasksView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/TasksView.java
new file mode 100644
index 00000000..9732a460
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/TasksView.java
@@ -0,0 +1,39 @@
+package org.gluster.storage.management.console.views;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.views.pages.TasksPage;
+import org.gluster.storage.management.core.model.TaskInfo;
+
+
+public class TasksView extends ViewPart {
+
+ public static final String ID = TasksView.class.getName();
+ private TasksPage page;
+
+
+ public TasksView() {
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ page = new TasksPage(getSite(), parent, SWT.NONE, getAllTasks());
+ page.layout(); // IMP: lays out the form properly
+ }
+
+
+ private List<TaskInfo> getAllTasks() {
+ return GlusterDataModelManager.getInstance().getModel().getCluster().getTaskInfoList();
+ }
+
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ViewsManager.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ViewsManager.java
new file mode 100644
index 00000000..76581416
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/ViewsManager.java
@@ -0,0 +1,38 @@
+/**
+ * ViewsManager.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.gluster.storage.management.core.model.Entity;
+
+/**
+ * Whenever the current selection/action demands opening different set of views, the views manager is used to open
+ * appropriate views.
+ */
+public interface ViewsManager {
+ /**
+ * Updates the views for given entity. This typically means that user is working with the given entity, and hence
+ * the views related to that entity should be made visible, and other un-related views should be hidden.
+ *
+ * @param entity
+ * The entity for which views are to be updated
+ */
+ public void updateViews(Entity entity);
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeBricksView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeBricksView.java
new file mode 100644
index 00000000..33f7c970
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeBricksView.java
@@ -0,0 +1,39 @@
+package org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.BricksPage;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class VolumeBricksView extends ViewPart {
+ public static final String ID = VolumeBricksView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private BricksPage page;
+ private Volume volume;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volume == null) {
+ volume = guiHelper.getSelectedEntity(getSite(), Volume.class);
+ }
+
+ createPage(parent);
+ }
+
+ /**
+ * @param parent
+ */
+ private void createPage(Composite parent) {
+ page = new BricksPage(parent, SWT.NONE, getSite(), volume.getBricks());
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+}
+
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeLogsView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeLogsView.java
new file mode 100644
index 00000000..eeffe6d5
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeLogsView.java
@@ -0,0 +1,58 @@
+package org.gluster.storage.management.console.views;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.VolumeLogsPage;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeLogMessage;
+import org.gluster.storage.management.core.utils.DateUtil;
+
+
+public class VolumeLogsView extends ViewPart implements IDoubleClickListener {
+ VolumeLogsPage logsPage;
+ public static final String ID = VolumeLogsView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Volume volume;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volume == null) {
+ volume = guiHelper.getSelectedEntity(getSite(), Volume.class);
+ }
+
+ createPage(parent);
+ }
+
+ private void createPage(Composite parent) {
+ logsPage = new VolumeLogsPage(parent, SWT.NONE, volume);
+ logsPage.addDoubleClickListener(this);
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ @Override
+ public void setFocus() {
+ logsPage.setFocus();
+ }
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ VolumeLogMessage volumeLogMessage = (VolumeLogMessage) ((StructuredSelection) event.getSelection())
+ .getFirstElement();
+ String message = DateUtil.formatDate(volumeLogMessage.getTimestamp()) + " "
+ + DateUtil.formatTime(volumeLogMessage.getTimestamp()) + " [" + volumeLogMessage.getSeverity() + "]"
+ + CoreConstants.NEWLINE + CoreConstants.NEWLINE + volumeLogMessage.getMessage();
+
+ new MessageDialog(getSite().getShell(), "Log message from " + volumeLogMessage.getBrick(), null, message,
+ MessageDialog.NONE, new String[] { "Close" }, 0).open();
+
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeOptionsView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeOptionsView.java
new file mode 100644
index 00000000..144f1441
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeOptionsView.java
@@ -0,0 +1,36 @@
+package org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.VolumeOptionsPage;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class VolumeOptionsView extends ViewPart {
+ public static final String ID = VolumeOptionsView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private VolumeOptionsPage page;
+ private Volume volume;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volume == null) {
+ volume = guiHelper.getSelectedEntity(getSite(), Volume.class);
+ }
+
+ createPage(parent);
+ }
+
+ private void createPage(Composite parent) {
+ page = new VolumeOptionsPage(parent, SWT.NONE, volume);
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+}
+
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeSummaryView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeSummaryView.java
new file mode 100644
index 00000000..2257c56f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeSummaryView.java
@@ -0,0 +1,859 @@
+package org.gluster.storage.management.console.views;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.FormText;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.toolbar.GlusterToolbarManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Partition;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.utils.NumberUtil;
+import org.gluster.storage.management.core.utils.StringUtil;
+import org.gluster.storage.management.core.utils.ValidationUtil;
+
+
+public class VolumeSummaryView extends ViewPart {
+ public static final String ID = VolumeSummaryView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private Volume volume;
+ private Label volumeType;
+ private CLabel lblStatusValue;
+ private DefaultClusterListener volumeChangedListener;
+ private Hyperlink changeLink;
+ private Hyperlink cifsChangeLink;
+ private Text accessControlText;
+ private Text cifsUsersText;
+ private ControlDecoration errDecoration;
+ private ControlDecoration errCifsDecoration;
+ private Composite parent;
+ private static final String COURIER_FONT = "Courier";
+ private GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+ private Cluster cluster = modelManager.getModel().getCluster();
+ private Button nfsCheckBox;
+ private FormText glusterNfsMountText;
+ private String nfsMountInfo;
+ private Label nfsLabel;
+ private String nfs;
+
+ private Label numberOfBricks;
+ private Label totalDiskSpace;
+ private Composite alertsSection;
+ private Button cifsCheckbox;
+ private Label cifsLabel;
+ private Composite cifsUpdateLinkComposite;
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volume == null) {
+ volume = guiHelper.getSelectedEntity(getSite(), Volume.class);
+ }
+
+ this.parent = parent;
+ setPartName("Summary");
+ createSections();
+
+ final GlusterToolbarManager toolbarManager = new GlusterToolbarManager(getSite().getWorkbenchWindow());
+ // Refresh the navigation tree whenever there is a change to the data model
+ volumeChangedListener = new DefaultClusterListener() {
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ updateVolumeStatusLabel();
+ populateAccessControlText();
+ changeNFSStatus(volume.isNfsEnabled());
+ updateBrickChanges(volume);
+ toolbarManager.updateToolbar(volume);
+ cifsCheckbox.setSelection(volume.isCifsEnable());
+ populateCifsUsersText();
+ renderVolumeTypeField();
+ }
+
+ @Override
+ public void alertsGenerated() {
+ super.alertsGenerated();
+ guiHelper.clearSection(alertsSection);
+ populateAlertSection();
+ alertsSection.layout();
+ }
+ };
+ modelManager.addClusterListener(volumeChangedListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ modelManager.removeClusterListener(volumeChangedListener);
+ }
+
+ private void createSections() {
+ form = guiHelper.setupForm(parent, toolkit, "Volume Properties [" + volume.getName() + "]");
+
+ createVolumePropertiesSection();
+ createVolumeMountingInfoSection();
+ createVolumeAlertsSection();
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ private void createVolumeAlertsSection() {
+ alertsSection = guiHelper.createSection(form, toolkit, "Alerts", null, 1, false);
+ populateAlertSection();
+ }
+
+ private void populateAlertSection() {
+ List<Alert> alerts = cluster.getAlerts();
+
+ for (int i = 0; i < alerts.size(); i++) {
+ if (alerts.get(i).getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT
+ && alerts.get(i).getReference().split(":")[0].trim().equals(volume.getName())) {
+ addAlertLabel(alertsSection, alerts.get(i));
+ }
+ }
+ }
+
+ private void addAlertLabel(Composite section, Alert alert) {
+ CLabel lblAlert = new CLabel(section, SWT.NONE);
+ lblAlert.setImage(guiHelper.getImage(IImageKeys.BRICK_OFFLINE_22x22));
+ lblAlert.setText(alert.getMessage());
+ lblAlert.redraw();
+ }
+
+ private FormText setFormTextStyle(FormText formText, String fontName, int size, int style) {
+ Font font = new Font(Display.getCurrent(), new FontData(fontName, size, style));
+ formText.setFont(font);
+ return formText;
+ }
+
+ private void createVolumeMountingInfoSection() {
+ String glusterFs = "Gluster:";
+ nfs = "NFS:";
+ String onlineServers = getOnlineServers(10); // Limited to 10 servers
+ String firstOnlineServer = onlineServers.split(",")[0].trim();
+ String glusterFsMountInfo = "mount -t glusterfs " + firstOnlineServer + ":/" + volume.getName()
+ + " <mount-point>";
+ nfsMountInfo = "mount -t nfs " + firstOnlineServer + ":/" + volume.getName() + " <mount-point>";
+ // TODO: if more than 10 servers...
+ String info = "Server can be any server name in the storage cloud eg. <" + onlineServers + ">";
+
+ Composite section = guiHelper.createSection(form, toolkit, "Mounting Information", null, 3, false);
+
+ toolkit.createLabel(section, glusterFs, SWT.NORMAL);
+ FormText glusterfsMountText = setFormTextStyle(toolkit.createFormText(section, true), COURIER_FONT, 10,
+ SWT.NONE);
+ glusterfsMountText.setText(glusterFsMountInfo, false, false);
+ glusterfsMountText.setLayoutData(new GridData(GridData.BEGINNING, GridData.VERTICAL_ALIGN_CENTER, false, false,
+ 2, 0)); // Label spanned two column
+
+ nfsLabel = toolkit.createLabel(section, nfs, SWT.NONE);
+ GridData data = new GridData();
+ data.horizontalAlignment = SWT.FILL;
+ nfsLabel.setLayoutData(data);
+
+ glusterNfsMountText = setFormTextStyle(toolkit.createFormText(section, true), COURIER_FONT, 10, SWT.NONE);
+ glusterNfsMountText.setText(nfsMountInfo, false, false);
+ glusterNfsMountText.setLayoutData(new GridData(GridData.BEGINNING, GridData.VERTICAL_ALIGN_CENTER, false,
+ false, 2, 0));
+
+ changeNFSStatus(nfsCheckBox.getSelection());
+
+ toolkit.createLabel(section, "");
+ Label infoLabel = toolkit.createLabel(section, info, SWT.NONE);
+ infoLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.VERTICAL_ALIGN_CENTER, false, false, 2, 0));
+
+ // TODO: implement a logic to identify the corresponding glusterfs client download link
+ String message = "You can download GlusterFS client from";
+ String glusterFSDownloadlinkText = "here.";
+ final String glusterFSDownloadlink = "http://download.gluster.com/pub/gluster/glusterfs/";
+
+ toolkit.createLabel(section, "");
+ toolkit.createLabel(section, message);
+ Hyperlink link = toolkit.createHyperlink(section, glusterFSDownloadlinkText, SWT.NORMAL);
+ link.addHyperlinkListener(new HyperlinkAdapter() {
+ public void linkActivated(HyperlinkEvent e) {
+ try {
+ System.out.println(e.getLabel() + " [" + e.getHref() + "]");
+ PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser()
+ .openURL(new URL(glusterFSDownloadlink));
+ } catch (PartInitException e1) {
+ e1.printStackTrace();
+ } catch (MalformedURLException e1) {
+ e1.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private String getOnlineServers(int maxServers) {
+ List<String> OnlineServers = new ArrayList<String>();
+ for (GlusterServer server : cluster.getServers()) {
+ if (server.getStatus() == SERVER_STATUS.ONLINE) {
+ OnlineServers.add(server.getName());
+ if (OnlineServers.size() >= maxServers) {
+ break;
+ }
+ }
+ }
+ return StringUtil.collectionToString(OnlineServers, ", ") + ((OnlineServers.size() > maxServers) ? "..." : "");
+ }
+
+ /**
+ *
+ */
+ private void createVolumePropertiesSection() {
+ Composite section = guiHelper.createSection(form, toolkit, "Properties", null, 3, false);
+
+ createVolumeTypeField(section);
+
+ VOLUME_TYPE volumeType = volume.getVolumeType();
+ if (volumeType == VOLUME_TYPE.DISTRIBUTED_REPLICATE) {
+ createReplicaCountField(section);
+ }
+
+ if (volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ createStripeCountField(section);
+ }
+
+ createNumOfBricksField(section);
+ createDiskSpaceField(section);
+ // createTransportTypeField(section);
+ createNASProtocolField(section);
+ createCifsField(section);
+ createAccessControlField(section);
+ createStatusField(section);
+ }
+
+ private GridData createDefaultLayoutData() {
+ GridData layoutData = new GridData();
+ layoutData.minimumWidth = 300;
+ layoutData.widthHint = 300;
+ return layoutData;
+ }
+
+ private void createCifsField(Composite section) {
+ cifsLabel = toolkit.createLabel(section, "CIFS: ", SWT.NONE);
+ cifsUsersText = toolkit.createText(section, volume.getAccessControlList(), SWT.BORDER);
+ populateCifsUsersText();
+ addKeyListenerForCifsUser();
+
+ cifsUpdateLinkComposite = toolkit.createComposite(section, SWT.NONE);
+ cifsUpdateLinkComposite.setLayout(new FillLayout());
+ cifsUpdateLinkComposite.setVisible(volume.isCifsEnable());
+
+ createChangeLinkForCifs(cifsUpdateLinkComposite);
+ renderCifsUsers(cifsCheckbox.getSelection());
+ errCifsDecoration = guiHelper.createErrorDecoration(cifsUsersText);
+ errCifsDecoration.hide();
+ }
+
+ private void createAccessControlField(Composite section) {
+ toolkit.createLabel(section, "Allow Access From: ", SWT.NONE);
+ accessControlText = toolkit.createText(section, volume.getAccessControlList(), SWT.BORDER);
+
+ populateAccessControlText();
+ addKeyListenerForAccessControl();
+ accessControlText.setLayoutData(createDefaultLayoutData());
+ accessControlText.setEnabled(false);
+ createChangeLinkForAccessControl(section);
+
+ // error decoration used while validating the access control text
+ errDecoration = guiHelper.createErrorDecoration(accessControlText);
+ errDecoration.hide();
+ createAccessControlInfoLabel(section); // info text
+ }
+
+ private void createAccessControlInfoLabel(Composite section) {
+ toolkit.createLabel(section, "", SWT.NONE);
+ Label accessControlInfoLabel = toolkit.createLabel(section, "(Comma separated list of IP addresses/hostnames)");
+ GridData data = new GridData(SWT.LEFT, SWT.CENTER, true, false);
+ data.horizontalSpan = 2;
+ accessControlInfoLabel.setLayoutData(data);
+ }
+
+ private void createChangeLinkForAccessControl(Composite section) {
+ changeLink = toolkit.createHyperlink(section, "change", SWT.NONE);
+ changeLink.addHyperlinkListener(new HyperlinkAdapter() {
+
+ private void finishEdit() {
+ saveAccessControlList();
+ }
+
+ private void startEdit() {
+ accessControlText.setEnabled(true);
+ accessControlText.setFocus();
+ accessControlText.selectAll();
+ changeLink.setText("update");
+ }
+
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ if (accessControlText.isEnabled()) {
+ // we were already in edit mode.
+ finishEdit();
+ } else {
+ // Get in to edit mode
+ startEdit();
+ }
+ }
+ });
+ }
+
+ private void saveAccessControlList() {
+ final String newACL = accessControlText.getText();
+
+ guiHelper.setStatusMessage("Setting access control list to [" + newACL + "]...");
+ parent.update();
+
+ if (newACL.equals(volume.getAccessControlList())) {
+ accessControlText.setEnabled(false);
+ changeLink.setText("change");
+ } else if (ValidationUtil.isValidAccessControl(newACL)) {
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+ @Override
+ public void run() {
+ try {
+ new VolumesClient().setVolumeOption(volume.getName(), Volume.OPTION_AUTH_ALLOW, newACL);
+ accessControlText.setEnabled(false);
+ changeLink.setText("change");
+
+ modelManager.setAccessControlList(volume, newACL);
+ } catch (Exception e) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Access control", e.getMessage());
+ }
+ }
+ });
+ } else {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Access control", "Invalid IP / Host name ");
+ }
+ guiHelper.clearStatusMessage();
+ parent.update();
+ }
+
+ private void createChangeLinkForCifs(Composite section) {
+ cifsChangeLink = toolkit.createHyperlink(section, "change", SWT.NONE);
+ cifsChangeLink.addHyperlinkListener(new HyperlinkAdapter() {
+
+ private void finishEdit() {
+ saveCifsConfiguration();
+ }
+
+ private void startEdit() {
+ if (cifsCheckbox.getSelection()) {
+ enableCifsUsersControls(true);
+ cifsUsersText.selectAll();
+ }
+ }
+
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ if (cifsUsersText.isEnabled()) {
+ // we were already in edit mode.
+ finishEdit();
+ } else {
+ // Get in to edit mode
+ startEdit();
+ }
+ }
+ });
+ }
+
+ private void saveCifsConfiguration() {
+ guiHelper.setStatusMessage("Setting Cifs Configuration...");
+ parent.update();
+
+ // To check if no changes in the users list
+ if (!isvalidCifsUser()) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Cifs Configuration",
+ "Please enter cifs users name");
+ enableCifsUsersControls(true);
+ validateCifsUsers();
+ // } else if (cifsUsers.equals(configuredUsers)) { // Nothing to do.
+ // enableCifsUsersControls(false);
+ } else {
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+ @Override
+ public void run() {
+ VolumesClient vc = new VolumesClient();
+ Volume newVolume = new Volume();
+ Integer userAction = 1;
+ String cifsUsers = cifsUsersText.getText().trim();
+ List<String> servers = GlusterDataModelManager.getInstance().getOfflineServers();
+ // One or more servers are offline, Show warning if cifs is enabled
+ if (servers != null && servers.size() > 0) {
+ userAction = new MessageDialog(parent.getShell(), "CIFS configuration", GUIHelper
+ .getInstance().getImage(IImageKeys.VOLUME_16x16),
+ "Performing CIFS updates when one or more servers are offline can trigger "
+ + "inconsistent behavior for CIFS accesses in the cluster."
+ + CoreConstants.NEWLINE + CoreConstants.NEWLINE
+ + "Are you sure you want to continue?", MessageDialog.QUESTION, new String[] {
+ "No", "Yes" }, -1).open();
+ }
+
+ // If no cifs users and removing cifs config, nothing to do
+ if (!(!cifsCheckbox.getSelection() && volume.getCifsUsers().toString().equals("[]") && (cifsUsers
+ .isEmpty() || cifsUsers.equals(""))) && userAction == 1) {
+ try {
+ vc.setCifsConfig(volume.getName(), cifsCheckbox.getSelection(), cifsUsers);
+ enableCifsUsersControls(false);
+ newVolume = vc.getVolume(volume.getName());
+ modelManager.volumeChanged(volume, newVolume);
+ showCifsUsersControls(volume.isCifsEnable());
+ } catch (Exception e) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Cifs Configuration",
+ e.getMessage());
+ cifsCheckbox.setSelection(volume.isCifsEnable());
+ enableCifsUsersControls(cifsCheckbox.getSelection());
+ populateCifsUsersText();
+ }
+ } else {
+ newVolume = vc.getVolume(volume.getName());
+ modelManager.volumeChanged(volume, newVolume);
+ showCifsUsersControls(volume.isCifsEnable());
+ }
+ }
+ });
+ }
+ guiHelper.clearStatusMessage();
+ parent.update();
+ }
+
+ private void saveNFSOption() {
+ guiHelper.setStatusMessage("Setting NFS option...");
+ parent.update();
+
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+ @Override
+ public void run() {
+ try {
+ boolean enableNfs = nfsCheckBox.getSelection();
+ new VolumesClient().setVolumeOption(volume.getName(), Volume.OPTION_NFS_DISABLE,
+ (enableNfs) ? GlusterConstants.OFF : GlusterConstants.ON);
+ modelManager.setNfsEnabled(volume, enableNfs);
+ } catch (Exception e) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "NFS Option", e.getMessage());
+ }
+ }
+ });
+ guiHelper.clearStatusMessage();
+ parent.update();
+ }
+
+ private void addKeyListenerForAccessControl() {
+ accessControlText.addKeyListener(new KeyAdapter() {
+ public void keyReleased(KeyEvent key) {
+ switch (key.keyCode) {
+ case SWT.ESC:
+ // Reset to default
+ populateAccessControlText();
+ changeLink.setText("change");
+ accessControlText.setEnabled(false);
+ break;
+ case 13:
+ // User has pressed enter. Save the new value
+ saveAccessControlList();
+ break;
+ }
+
+ validateAccessControlList();
+ }
+ });
+ }
+
+ private void populateAccessControlText() {
+ String accessControlList = volume.getAccessControlList();
+ if (accessControlList == null) {
+ // if not set, show default value
+ accessControlList = modelManager.getVolumeOptionDefaultValue(Volume.OPTION_AUTH_ALLOW);
+ }
+ accessControlText.setText(accessControlList);
+ }
+
+ private void addKeyListenerForCifsUser() {
+ cifsUsersText.addKeyListener(new KeyAdapter() {
+ public void keyReleased(KeyEvent key) {
+ switch (key.keyCode) {
+ case SWT.ESC:
+ // Reset to default
+ populateCifsUsersText();
+ enableCifsUsersControls(false);
+ if (cifsUsersText.getText().trim().length() == 0) { // Disable CIFS as well
+ cifsCheckbox.setSelection(false);
+ }
+ form.reflow(true);
+ break;
+ case 13:
+ // User has pressed enter. Save the new value
+ saveCifsConfiguration();
+ break;
+ }
+ validateCifsUsers();
+ }
+ });
+ }
+
+ private void populateCifsUsersText() {
+ List<String> userList = volume.getCifsUsers();
+ if (volume.isCifsEnable() && userList != null) {
+ cifsUsersText.setText(StringUtil.collectionToString(userList, ","));
+ } else {
+ cifsUsersText.setText("");
+ }
+ }
+
+ private void createNASProtocolField(final Composite section) {
+ toolkit.createLabel(section, "Access Protocols: ", SWT.NONE);
+
+ Composite nasProtocolsComposite = toolkit.createComposite(section);
+ nasProtocolsComposite.setLayout(new FillLayout());
+
+ createCheckbox(nasProtocolsComposite, "Gluster", true, false);
+
+ nfsCheckBox = createCheckbox(nasProtocolsComposite, "NFS", volume.isNfsEnabled(), true);
+
+ nfsCheckBox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (!nfsCheckBox.getSelection()) {
+ Integer userAction = new MessageDialog(parent.getShell(), "NFS Re-export", GUIHelper.getInstance()
+ .getImage(IImageKeys.VOLUME_16x16),
+ "Are you sure you want to stop the NFS Re-export for volume [" + volume.getName() + "]?",
+ MessageDialog.QUESTION, new String[] { "No", "Yes" }, -1).open();
+ if (userAction <= 0) { // user select cancel or pressed escape key
+ nfsCheckBox.setSelection(true);
+ return;
+ }
+ }
+ saveNFSOption();
+ }
+ });
+
+ // CIFS checkbox
+ cifsCheckbox = createCheckbox(nasProtocolsComposite, "CIFS", volume.isCifsEnable(), true);
+ createCifsCheckboxListner(cifsCheckbox);
+
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createCifsCheckboxListner(final Button cifsCheckbox) {
+ cifsCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (cifsCheckbox.getSelection()) {
+ // need to enable cifs
+ // TODO: Open the text box (empty and enabled),
+ // the hyperlink next to the textbox should have label "update"
+ // when user clicks on that hyperlink,
+ // saveCifsConfiguration should be called
+ // Also, if user presses the "ESC" key,
+ // return to the previous state of checkbox and hide the textbox + hyperlink
+ showCifsUsersControls(true);
+ enableCifsUsersControls(true);
+ // saveCifsConfiguration();
+ } else {
+ // need to disable cifs
+ // TODO: hide the textbox and the link AFTER disabling cifs
+ if ((volume.getCifsUsers() == null || volume.getCifsUsers().toString().equals("[]"))
+ && cifsUsersText.getText().trim().equals("")) {
+ showCifsUsersControls(false);
+ enableCifsUsersControls(false);
+ } else {
+
+ Integer userAction = new MessageDialog(parent.getShell(), "CIFS Re-export", GUIHelper
+ .getInstance().getImage(IImageKeys.VOLUME_16x16),
+ "Are you sure you want to stop the CIFS re-export for volume [" + volume.getName()
+ + "]?", MessageDialog.QUESTION, new String[] { "No", "Yes" }, -1).open();
+ if (userAction <= 0) { // user select cancel or pressed escape key
+ cifsCheckbox.setSelection(true); // back to previous state.
+ } else {
+ showCifsUsersControls(false);
+ enableCifsUsersControls(false);
+ saveCifsConfiguration();
+ }
+ }
+ }
+ populateCifsUsersText();
+ form.reflow(true);
+ }
+ });
+ }
+
+ private void renderCifsUsers(Boolean cifsSelection) {
+ if (cifsSelection) {
+ enableCifsUsersControls(false);
+ showCifsUsersControls(true);
+ } else {
+ showCifsUsersControls(false);
+ }
+ }
+
+ private void showCifsUsersControls(Boolean visible) {
+ if (visible) {
+ GridData data = new GridData();
+ data.heightHint = 20;
+ data.widthHint = 100;
+ cifsLabel.setLayoutData(data);
+
+ GridData data1 = new GridData();
+ data1.heightHint = 20;
+ data1.widthHint = 300;
+
+ cifsUsersText.setLayoutData(data1);
+
+ GridData data2 = new GridData();
+ data2.heightHint = 25;
+ data2.widthHint = 75;
+ cifsUpdateLinkComposite.setLayoutData(data2);
+ } else {
+ GridData data = new GridData();
+ data.heightHint = 0;
+
+ cifsLabel.setLayoutData(data);
+ cifsUsersText.setLayoutData(data);
+ cifsUpdateLinkComposite.setLayoutData(data);
+ }
+
+ cifsLabel.setVisible(visible);
+ cifsUsersText.setVisible(visible);
+ cifsUpdateLinkComposite.setVisible(visible);
+ form.reflow(true);
+ }
+
+ private void enableCifsUsersControls(Boolean enable) {
+ cifsUsersText.setEnabled(enable);
+ cifsChangeLink.setText((enable) ? "update" : "change");
+ if (enable) {
+ cifsUsersText.setFocus();
+ validateCifsUsers();
+ } else {
+ if (errCifsDecoration != null) {
+ errCifsDecoration.hide();
+ }
+ }
+ }
+
+ private Button createCheckbox(Composite parent, String label, boolean checked, boolean enabled) {
+ final Button checkBox = toolkit.createButton(parent, label, SWT.CHECK);
+ checkBox.setSelection(checked);
+ checkBox.setEnabled(enabled);
+ return checkBox;
+ }
+
+ private void changeNFSStatus(Boolean isNFSExported) {
+ glusterNfsMountText.setVisible(isNFSExported);
+ nfsLabel.setVisible(isNFSExported);
+ nfsCheckBox.setSelection(isNFSExported);
+ }
+
+ private void updateBrickChanges(Volume volume) {
+ numberOfBricks.setText("" + volume.getNumOfBricks());
+ totalDiskSpace.setText("" + NumberUtil.formatNumber(getTotalDiskSpace() / 1024));
+ }
+
+ private double getDiskSize(String serverName, String deviceName) {
+ double diskSize = 0;
+ GlusterServer server = cluster.getServer(serverName);
+ if (server.getStatus() == SERVER_STATUS.ONLINE) {
+ for (Disk disk : server.getDisks()) {
+ if (disk.getName().equals(deviceName)) {
+ diskSize = disk.getSpace();
+ break;
+ }
+
+ if (disk.hasPartitions()) {
+ for (Partition partition : disk.getPartitions()) {
+ if (partition.getName().equals(deviceName)) {
+ diskSize = partition.getSpace();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return diskSize;
+ }
+
+ private double getTotalDiskSpace() {
+ List<Double> diskSizes = getVolumeDiskSizes();
+ VOLUME_TYPE volumeType = volume.getVolumeType();
+ double diskSize = 0d;
+ if (volumeType == VOLUME_TYPE.DISTRIBUTE || volumeType == VOLUME_TYPE.STRIPE
+ || volumeType == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ for (Double size : diskSizes) {
+ diskSize += size;
+ }
+ } else { // Replicate or distributed replicate
+ int replicaCount = volume.getReplicaCount();
+ if (replicaCount == 0) {
+ replicaCount = Volume.DEFAULT_REPLICA_COUNT;
+ }
+ int startIndex = 0;
+ for (int i = 0; i < (diskSizes.size() / replicaCount); i++) {
+ startIndex = i * replicaCount;
+ diskSize += Collections.min(diskSizes.subList(startIndex, startIndex + replicaCount));
+ }
+ }
+ return diskSize;
+ }
+
+ private List<Double> getVolumeDiskSizes() {
+ List<Double> diskSizes = new ArrayList<Double>();
+ Device device;
+ for (Brick brick : volume.getBricks()) {
+ device = modelManager.getDeviceForBrickDir(brick);
+ diskSizes.add( (device == null) ? 0d : getDiskSize(brick.getServerName(), device.getName()) );
+ }
+ return diskSizes;
+ }
+
+
+
+ private void createDiskSpaceField(Composite section) {
+ Label diskSpaceLabel = toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE);
+ diskSpaceLabel.setToolTipText("<b>bold</b>normal");
+ totalDiskSpace = toolkit.createLabel(section,
+ "" + NumberUtil.formatNumber(getTotalDiskSpace() / 1024), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createStatusField(Composite section) {
+ toolkit.createLabel(section, "Status: ", SWT.NONE);
+
+ lblStatusValue = new CLabel(section, SWT.NONE);
+ updateVolumeStatusLabel();
+
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void updateVolumeStatusLabel() {
+ lblStatusValue.setText(volume.getStatusStr());
+ lblStatusValue.setImage((volume.getStatus() == Volume.VOLUME_STATUS.ONLINE) ? guiHelper
+ .getImage(IImageKeys.STATUS_ONLINE_16x16) : guiHelper.getImage(IImageKeys.STATUS_OFFLINE_16x16));
+ GridData data = new GridData();
+ data.horizontalAlignment = SWT.FILL;
+ lblStatusValue.setLayoutData(data);
+ lblStatusValue.redraw();
+ }
+
+ private void createTransportTypeField(Composite section) {
+ toolkit.createLabel(section, "Transport Type: ", SWT.NONE);
+ toolkit.createLabel(section, "" + volume.getTransportTypeStr(), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createNumOfBricksField(Composite section) {
+ toolkit.createLabel(section, "Number of Bricks: ", SWT.NONE);
+ numberOfBricks = toolkit.createLabel(section, "" + volume.getNumOfBricks(), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createStripeCountField(Composite section) {
+ toolkit.createLabel(section, "Stripe Count: ", SWT.NONE);
+ toolkit.createLabel(section, "" + volume.getStripeCount(), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createReplicaCountField(Composite section) {
+ toolkit.createLabel(section, "Replica Count: ", SWT.NONE);
+ toolkit.createLabel(section, "" + volume.getReplicaCount(), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE); // dummy
+ }
+
+ private void createVolumeTypeField(Composite section) {
+ toolkit.createLabel(section, "Volume Type: ", SWT.NONE);
+ volumeType = toolkit.createLabel(section, volume.getVolumeTypeStr(), SWT.NONE);
+ toolkit.createLabel(section, "", SWT.NONE);
+ }
+
+ private void renderVolumeTypeField() {
+ volumeType.setText(volume.getVolumeTypeStr());
+ }
+
+ @Override
+ public void setFocus() {
+ form.setFocus();
+ }
+
+ private void validateAccessControlList() {
+ errDecoration.hide();
+
+ if (accessControlText.getText().length() == 0) {
+ errDecoration.setDescriptionText("Access control list cannot be empty!");
+ errDecoration.show();
+ return;
+ }
+
+ if (!ValidationUtil.isValidAccessControl(accessControlText.getText())) {
+ errDecoration.setDescriptionText("Invalid IP address/Host name ["
+ + ValidationUtil.getInvalidIpOrHostname(accessControlText.getText())
+ + "]. Please enter a valid value!");
+ errDecoration.show();
+ }
+ }
+
+ private void validateCifsUsers() {
+ errCifsDecoration.hide();
+ if (cifsCheckbox.getSelection()) {
+ String cifsUserList = cifsUsersText.getText().trim();
+ if (cifsUserList.length() == 0) {
+ errCifsDecoration.setDescriptionText("Please enter cifs user name");
+ errCifsDecoration.show();
+ }
+ }
+ }
+
+ private boolean isvalidCifsUser() {
+ if (cifsCheckbox.getSelection()) {
+ String cifsUserList = cifsUsersText.getText().trim();
+ return (cifsUserList.length() != 0);
+ }
+ validateCifsUsers();
+ return true;
+ }
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeView.java
new file mode 100644
index 00000000..27df48c1
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumeView.java
@@ -0,0 +1,90 @@
+/**
+ * DiscoveredServerView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.utils.NumberUtil;
+
+
+/**
+ * @author root
+ *
+ */
+public class VolumeView extends ViewPart {
+ public static final String ID = VolumeView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private Server server;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ if (server == null) {
+ server = guiHelper.getSelectedEntity(getSite(), Server.class);
+ }
+ createSections(parent, server, toolkit);
+ }
+
+ private void createServerSummarySection(Server server, FormToolkit toolkit, final ScrolledForm form) {
+ Composite section = guiHelper.createSection(form, toolkit, "Summary", null, 2, false);
+
+ toolkit.createLabel(section, "Number of CPUs: ", SWT.NONE);
+ toolkit.createLabel(section, "" + server.getNumOfCPUs(), SWT.NONE);
+
+ toolkit.createLabel(section, "Total Memory (GB): ", SWT.NONE);
+ toolkit.createLabel(section, "" + server.getTotalMemory(), SWT.NONE);
+
+ toolkit.createLabel(section, "Total Disk Space (GB): ", SWT.NONE);
+ toolkit.createLabel(section, "" + NumberUtil.formatNumber(server.getTotalDiskSpace()), SWT.NONE);
+ }
+
+ private void createSections(Composite parent, Server server, FormToolkit toolkit) {
+ String serverName = server.getName();
+ form = guiHelper.setupForm(parent, toolkit, "Discovered Server Summary [" + serverName + "]");
+ createServerSummarySection(server, toolkit, form);
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ if (form != null) {
+ form.setFocus();
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesSummaryView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesSummaryView.java
new file mode 100644
index 00000000..549353e8
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesSummaryView.java
@@ -0,0 +1,301 @@
+/**
+ * VolumesSummaryView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IImageKeys;
+import org.gluster.storage.management.console.utils.ChartViewerComposite;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.Alert;
+import org.gluster.storage.management.core.model.Cluster;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+
+
+/**
+ *
+ */
+public class VolumesSummaryView extends ViewPart {
+ public static final String ID = VolumesSummaryView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private ScrolledForm form;
+ private EntityGroup<Volume> volumes;
+ private Cluster cluster = GlusterDataModelManager.getInstance().getModel().getCluster();
+ private ClusterListener clusterListener;
+
+ private static final String ALERTS = "Alerts";
+ private static final String VOLUMES_SUMMARY = "Volumes - Summary";
+ private static final String AVAILABILITY = "Availability";
+ private Composite alertsSection;
+ private Composite tasksSection;
+ private Composite summarySection;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets
+ * .Composite)
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volumes == null) {
+ Object selectedObj = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ if (selectedObj != null && ((EntityGroup) selectedObj).getEntityType() == Volume.class) {
+ volumes = (EntityGroup<Volume>) selectedObj;
+ }
+ }
+
+ setPartName("Summary");
+ createSections(parent);
+
+ clusterListener = new DefaultClusterListener() {
+ @Override
+ public void volumeCreated(Volume volume) {
+ super.volumeCreated(volume);
+ updateSummarySection();
+ }
+
+ @Override
+ public void volumeDeleted(Volume volume) {
+ super.volumeDeleted(volume);
+ updateSummarySection();
+ }
+
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ super.volumeChanged(volume, event);
+ updateSummarySection();
+ }
+
+ private void updateAlertSection() {
+ guiHelper.clearSection(alertsSection);
+ populateAlertSection();
+ }
+
+ private void updateSummarySection() {
+ guiHelper.clearSection(summarySection);
+ populateSummarySection();
+ summarySection.layout();
+ form.reflow(true);
+ }
+
+ @Override
+ public void alertsGenerated() {
+ super.alertsGenerated();
+ guiHelper.clearSection(alertsSection);
+ populateAlertSection();
+ }
+
+ @Override
+ public void alertRemoved(Alert alert) {
+ super.alertRemoved(alert);
+ updateAlertSection();
+ }
+
+ @Override
+ public void alertCreated(Alert alert) {
+ super.alertCreated(alert);
+ updateAlertSection();
+ }
+
+ @Override
+ public void taskAdded(TaskInfo taskInfo) {
+ super.taskAdded(taskInfo);
+ updateTasksSection();
+ }
+
+ @Override
+ public void taskRemoved(TaskInfo taskInfo) {
+ super.taskRemoved(taskInfo);
+ updateTasksSection();
+ }
+
+ @Override
+ public void taskUpdated(TaskInfo taskInfo) {
+ super.taskUpdated(taskInfo);
+ updateTasksSection();
+ }
+
+ private void updateTasksSection() {
+ guiHelper.clearSection(tasksSection);
+ populateTasks();
+ }
+ };
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+
+ private void createSections(Composite parent) {
+ form = guiHelper.setupForm(parent, toolkit, VOLUMES_SUMMARY);
+ createSummarySection();
+ createTasksSection();
+ createAlertsSection();
+
+ parent.layout(); // IMP: lays out the form properly
+ }
+
+ private void createAlertsSection() {
+ alertsSection = guiHelper.createSection(form, toolkit, ALERTS, null, 1, false);
+ populateAlertSection();
+ }
+
+ private void populateAlertSection() {
+ for (Alert alert : cluster.getAlerts()) {
+ if (alert.getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_BRICKS_ALERT
+ || alert.getType() == Alert.ALERT_TYPES.OFFLINE_VOLUME_ALERT) {
+ addAlertLabel(alertsSection, alert);
+ }
+ }
+ alertsSection.pack(true);
+ form.reflow(true);
+ }
+
+ private void addAlertLabel(Composite section, Alert alert) {
+ CLabel lblAlert = new CLabel(section, SWT.NONE);
+
+ Image alertImage = null;
+ switch (alert.getType()) {
+ case OFFLINE_VOLUME_BRICKS_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.BRICK_OFFLINE_22x22);
+ break;
+ case OFFLINE_VOLUME_ALERT:
+ alertImage = guiHelper.getImage(IImageKeys.VOLUME_OFFLINE_22x22);
+ break;
+ }
+ lblAlert.setImage(alertImage);
+ lblAlert.setText(alert.getMessage());
+ lblAlert.redraw();
+ }
+
+ private void createTasksSection() {
+ tasksSection = guiHelper.createSection(form, toolkit, CoreConstants.RUNNING_TASKS, null, 1, false);
+ populateTasks();
+ }
+
+ private void populateTasks() {
+ for (TaskInfo taskInfo : cluster.getTaskInfoList()) {
+ if ((taskInfo.getType() == TASK_TYPE.BRICK_MIGRATE || taskInfo.getType() == TASK_TYPE.VOLUME_REBALANCE)
+ && taskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS)
+ addTaskLabel(tasksSection, taskInfo);
+ }
+ tasksSection.pack(true);
+ form.reflow(true);
+ }
+
+ private void addTaskLabel(Composite section, TaskInfo taskInfo) {
+ // Task related to Volumes context
+ if (taskInfo.getStatus().isPercentageSupported()) {
+ // TODO Progress bar or link to progress view
+ }
+
+ CLabel lblTask = new CLabel(section, SWT.NONE);
+ String description = taskInfo.getDescription();
+ switch (taskInfo.getStatus().getCode()) {
+ case Status.STATUS_CODE_PAUSE:
+ description += " (paused)";
+ break;
+ case Status.STATUS_CODE_COMMIT_PENDING:
+ description += " (commit pending)";
+ break;
+ case Status.STATUS_CODE_FAILURE:
+ description += " (failed)";
+ break;
+ }
+ lblTask.setText(description);
+ lblTask.setImage((taskInfo.getType() == TASK_TYPE.BRICK_MIGRATE) ? guiHelper
+ .getImage(IImageKeys.BRICK_MIGRATE_32x32) : guiHelper.getImage(IImageKeys.VOLUME_REBALANCE_32x32));
+ lblTask.redraw();
+ }
+
+ private void createSummarySection() {
+ summarySection = guiHelper.createSection(form, toolkit, AVAILABILITY, null, 2, false);
+ populateSummarySection();
+ }
+
+ private void populateSummarySection() {
+ if(volumes.getEntities().size() == 0) {
+ toolkit.createLabel(summarySection,
+ "This section will be populated after at least" + CoreConstants.NEWLINE +"one volume is created the storage cloud.");
+ return;
+ }
+
+ Double[] values = new Double[] { Double.valueOf(getVolumeCountByStatus(volumes, VOLUME_STATUS.ONLINE)),
+ Double.valueOf(getVolumeCountByStatus(volumes, VOLUME_STATUS.OFFLINE)) };
+ createStatusChart(toolkit, summarySection, values);
+ }
+
+ private int getVolumeCountByStatus(EntityGroup<Volume> volumes, VOLUME_STATUS status) {
+ int count = 0;
+ for (Volume volume : volumes.getEntities()) {
+ if (volume.getStatus() == status) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private void createStatusChart(FormToolkit toolkit, Composite section, Double[] values) {
+ String[] categories = new String[] { "Online", "Offline" };
+ ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, categories, values);
+
+ GridData data = new GridData(SWT.FILL, SWT.FILL, false, false);
+ data.widthHint = 300;
+ data.heightHint = 150;
+ chartViewerComposite.setLayoutData(data);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ if (form != null) {
+ form.setFocus();
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesView.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesView.java
new file mode 100644
index 00000000..41ccba1d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/VolumesView.java
@@ -0,0 +1,80 @@
+/**
+ * DiscoveredServersView.java
+ *
+ * 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 org.gluster.storage.management.console.views;
+
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.views.pages.VolumesPage;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Volume;
+
+
+/**
+ *
+ */
+public class VolumesView extends ViewPart implements IDoubleClickListener {
+ public static final String ID = VolumesView.class.getName();
+ private static final GUIHelper guiHelper = GUIHelper.getInstance();
+ private EntityGroup<Volume> volumes;
+ private VolumesPage page;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public void createPartControl(Composite parent) {
+ if (volumes == null) {
+ Object selectedObj = guiHelper.getSelectedEntity(getSite(), EntityGroup.class);
+ if (selectedObj != null && ((EntityGroup) selectedObj).getEntityType() == Volume.class) {
+ volumes = (EntityGroup<Volume>)selectedObj;
+ }
+ }
+
+ page = new VolumesPage(parent, getSite(), volumes);
+ page.addDoubleClickListener(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ page.setFocus();
+ }
+
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ NavigationView clusterView = (NavigationView) guiHelper.getView(NavigationView.ID);
+ if (clusterView != null) {
+ clusterView.selectEntity((Entity) ((StructuredSelection) event.getSelection()).getFirstElement());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractDisksPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractDisksPage.java
new file mode 100644
index 00000000..6d2959d2
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractDisksPage.java
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.widgets.ImageHyperlink;
+import org.gluster.storage.management.client.GlusterServersClient;
+import org.gluster.storage.management.client.TasksClient;
+import org.gluster.storage.management.console.Application;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.IEntityListener;
+import org.gluster.storage.management.console.dialogs.InitDiskDialog;
+import org.gluster.storage.management.console.utils.GlusterLogger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Device;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.Device.DEVICE_STATUS;
+import org.gluster.storage.management.core.model.Event.EVENT_TYPE;
+
+
+public abstract class AbstractDisksPage extends AbstractTableTreeViewerPage<Disk> implements IEntityListener {
+ protected List<Disk> disks;
+ protected static final GlusterLogger logger = GlusterLogger.getInstance();
+
+ /**
+ * @return Index of the "status" column in the table. Return -1 if status column is not displayed
+ */
+ protected abstract int getStatusColumnIndex();
+
+ public AbstractDisksPage(final Composite parent, int style, IWorkbenchSite site, List<Disk> disks) {
+ super(site, parent, style, false, true, disks);
+ this.disks = disks;
+
+ // creates hyperlinks for "uninitialized" disks
+ setupStatusCellEditor();
+ // Listen for disk status change events
+ Application.getApplication().addEntityListener(this);
+ }
+
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+ @Override
+ public void serverChanged(GlusterServer server, Event event) {
+ super.serverChanged(server, event);
+ EVENT_TYPE eventType = event.getEventType();
+ switch (eventType) {
+ case DEVICES_REMOVED:
+ case DEVICES_ADDED:
+ case DEVICES_CHANGED:
+ case GLUSTER_SERVER_CHANGED:
+ treeViewer.refresh(true);
+ default:
+ break;
+ }
+ }
+ };
+ }
+
+ private void createInitializeLink(final TreeItem item, final int rowNum, final Device uninitializedDevice) {
+ final Tree tree = treeViewer.getTree();
+ final TreeEditor editor = new TreeEditor(tree);
+ editor.grabHorizontal = true;
+ editor.horizontalAlignment = SWT.RIGHT;
+
+ tree.addPaintListener(new PaintListener() {
+ private TreeItem myItem = item;
+ private int myRowNum = rowNum;
+ private ImageHyperlink myLink = null;
+ private TreeEditor myEditor = null;
+
+ private void createLinkFor(Device uninitializedDevice, TreeItem item1, int rowNum1) {
+ myItem = item1;
+ myRowNum = rowNum1;
+
+ myEditor = new TreeEditor(tree);
+ myEditor.grabHorizontal = true;
+ myEditor.horizontalAlignment = SWT.RIGHT;
+
+ myLink = toolkit.createImageHyperlink(tree, SWT.NONE);
+ // link.setImage(guiHelper.getImage(IImageKeys.DISK_UNINITIALIZED));
+ myLink.setText("Initialize");
+ myLink.addHyperlinkListener(new StatusLinkListener(myLink, myEditor, treeViewer, uninitializedDevice));
+
+ myEditor.setEditor(myLink, item1, getStatusColumnIndex());
+
+ myItem.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ myLink.dispose();
+ myEditor.dispose();
+ }
+ });
+ }
+
+ @Override
+ public void paintControl(PaintEvent e) {
+ int itemCount = tree.getItemCount();
+
+ // Find the table item corresponding to our disk
+
+ Device device = null;
+ int rowNum1 = -1;
+ TreeItem item1 = null;
+
+ mainloop:
+ for (int i = 0; i < itemCount; i++) {
+ item1 = tree.getItem(i);
+
+ device = (Device) item1.getData();
+ if (device != null && device == uninitializedDevice) {
+ // this is an uninitialized "disk"
+ rowNum1 = i;
+ break;
+ }
+
+ int partitionCount = item1.getItemCount();
+ for(int j = 0; j < partitionCount; j++) {
+ TreeItem partitionItem = item1.getItem(j);
+ // check each partition
+ Device partition = (Device)partitionItem.getData();
+ if(partition != null && partition == uninitializedDevice) {
+ // this is an uninitialized "partition"
+ rowNum1 = i + j;
+ item1 = partitionItem;
+ device = partition;
+ // found the uninitialized device. break out.
+ break mainloop;
+ }
+ }
+ }
+
+ if (rowNum1 == -1) {
+ // item disposed and disk not visible. nothing to do.
+ return;
+ }
+
+ if (myEditor == null || myItem.isDisposed()) {
+ // item visible, and
+ // either editor never created, OR
+ // old item disposed. create the link for it
+ createLinkFor(device, item1, rowNum1);
+ }
+
+ if (rowNum1 != myRowNum) {
+ // disk visible, but at a different row num. re-create the link
+ myLink.dispose();
+ myEditor.dispose();
+ createLinkFor(device, item1, rowNum1);
+ }
+
+ myEditor.layout(); // IMPORTANT. Without this, the link location goes for a toss on maximize + restore
+ }
+ });
+ }
+
+ private void setupStatusCellEditor() {
+ final TreeViewer viewer = treeViewer;
+ final Tree tree = viewer.getTree();
+ int rowNum = 0;
+ for (int i = 0; i < tree.getItemCount(); i++, rowNum++) {
+ final TreeItem item = tree.getItem(i);
+ if (item.isDisposed() || item.getData() == null) {
+ continue;
+ }
+ final Disk disk = (Disk) item.getData();
+ if (disk.isUninitialized()) {
+ createInitializeLink(item, rowNum, disk);
+ }
+
+ if (disk.hasPartitions()) {
+ for(int j = 0; j < disk.getPartitions().size(); j++, rowNum++) {
+ TreeItem partitionItem = item.getItem(j);
+ // check each partition
+ Device partition = (Device)partitionItem.getData();
+ if (partition.isUninitialized()) {
+ createInitializeLink(partitionItem, rowNum, partition);
+ }
+ }
+ }
+ }
+ }
+
+ private final class StatusLinkListener extends HyperlinkAdapter {
+ private final Device device;
+ private final TreeEditor myEditor;
+ private final ImageHyperlink myLink;
+ private final TreeViewer viewer;
+
+ private StatusLinkListener(ImageHyperlink link, TreeEditor editor, TreeViewer viewer, Device device) {
+ this.device = device;
+ this.viewer = viewer;
+ this.myEditor = editor;
+ this.myLink = link;
+ }
+
+ private void updateStatus(final DEVICE_STATUS status, final boolean disposeEditor) {
+ if (disposeEditor) {
+ myLink.dispose();
+ myEditor.dispose();
+ }
+ device.setStatus(status);
+ viewer.update(device, new String[] { "status" });
+ Application.getApplication().entityChanged(device, new String[] { "status" });
+ }
+
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ GlusterDataModelManager modelManager = GlusterDataModelManager.getInstance();
+
+ // If the same task is already running return
+ String reference = device.getServerName() + ":" + device.getName();
+ TaskInfo existingTaskInfo = modelManager.getTaskByReference(reference);
+ if (existingTaskInfo != null && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_SUCCESS
+ && existingTaskInfo.getStatus().getCode() != Status.STATUS_CODE_FAILURE) {
+ MessageDialog.openInformation(getShell(), "Initialize disk - Error", "Initializing disk [" + reference
+ + "] is already in progress! Try later.");
+ return;
+ }
+
+ // To collect the available fsType
+ GlusterServersClient serversClient = new GlusterServersClient();
+ List<String> fsTypes = new ArrayList<String>();
+ try {
+ fsTypes = serversClient.getFSTypes(device.getServerName());
+ } catch (GlusterRuntimeException e1) {
+ MessageDialog.openError(getShell(), "Initialize disk - Error", e1.getMessage());
+ return;
+ }
+
+ InitDiskDialog formatDialog = new InitDiskDialog(getShell(), device.getName(), fsTypes);
+ int userAction = formatDialog.open();
+ if (userAction == Window.CANCEL) {
+ // formatDialog.cancelPressed();
+ return;
+ }
+
+ try {
+
+ URI uri = serversClient.initializeDisk(device.getServerName(), device.getName(), formatDialog.getFSType(), formatDialog.getMountPoint());
+
+ TasksClient taskClient = new TasksClient();
+ TaskInfo taskInfo = taskClient.getTaskInfo(uri);
+
+ if (taskInfo != null) {
+ modelManager.addTask(taskInfo);
+ }
+
+ if (taskInfo.getStatus().getCode() == Status.STATUS_CODE_RUNNING) {
+ updateStatus(DEVICE_STATUS.INITIALIZING, true);
+ } else if (taskInfo.getStatus().getCode() == Status.STATUS_CODE_SUCCESS) {
+ // If format completed (instantly), get the server details and update the server in the model
+ GlusterServer oldServer = modelManager.getModel().getCluster().getServer(device.getServerName());
+ GlusterServer newServer = serversClient.getGlusterServer(device.getServerName());
+ modelManager.glusterServerChanged(oldServer, newServer);
+ // updateStatus(DEVICE_STATUS.INITIALIZED, true);
+ // GlusterDataModelManager.getInstance().updateDeviceStatus(device.getServerName(), device.getName(),
+ // DEVICE_STATUS.INITIALIZED);
+ } else {
+ MessageDialog.openError(getShell(), "Initialize disk - Error", taskInfo.getStatus().getMessage());
+ }
+ guiHelper.showTaskView();
+ } catch (Exception e1) {
+ logger.error("Exception while initialize disk", e1);
+ MessageDialog.openError(getShell(), "Initialize disk - Error", e1.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void entityChanged(final Entity entity, final String[] paremeters) {
+ if (!(entity instanceof Device)) {
+ return;
+ }
+ final Device device = (Device) entity;
+
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ treeViewer.update(device, paremeters);
+
+ if (device.isUninitialized()) {
+ Tree tree = treeViewer.getTree();
+
+ for (int rowNum = 0; rowNum < tree.getItemCount(); rowNum++) {
+ TreeItem item = tree.getItem(rowNum);
+ if (item.getData() == device) {
+ createInitializeLink(item, rowNum, device);
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableTreeViewerPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableTreeViewerPage.java
new file mode 100644
index 00000000..55535637
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableTreeViewerPage.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TreeColumnLayout;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.Disk;
+
+
+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();
+ protected Composite parent;
+ protected IWorkbenchSite site;
+ private ClusterListener clusterListener;
+
+ private Text filterText;
+
+ private void setupPageLayout() {
+ final GridLayout layout = new GridLayout(1, false);
+ layout.verticalSpacing = 10;
+ layout.marginTop = 10;
+ setLayout(layout);
+ }
+
+ private Composite createTreeViewerComposite() {
+ Composite tableViewerComposite = new Composite(this, SWT.NO);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ GridData layoutData = new GridData();
+ layoutData.horizontalSpan=5;
+ layoutData.grabExcessHorizontalSpace = true;
+ layoutData.horizontalAlignment = SWT.FILL;
+ layoutData.verticalAlignment = SWT.FILL;
+ layoutData.grabExcessVerticalSpace = true;
+ tableViewerComposite.setLayoutData(layoutData);
+
+ return tableViewerComposite;
+ }
+
+
+ public AbstractTableTreeViewerPage(IWorkbenchSite site, final Composite parent, int style, boolean useChechboxes,
+ boolean multiSelection, List<Disk> allDisks) {
+ super(parent, style);
+
+ setupPageLayout();
+ //new FormToolkit(Display.getCurrent()).createButton(this, "test1", SWT.PUSH);
+
+ this.parent = parent;
+ this.site = site;
+
+ toolkit.adapt(this);
+ toolkit.paintBordersFor(this);
+
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ parent.setLayoutData(data);
+
+ filterText = guiHelper.createFilterText(toolkit, this);
+
+ Composite tableViewerComposite = createTreeViewerComposite();
+ createTreeViewer(allDisks, tableViewerComposite);
+ parent.layout(); // Important - this actually paints the table
+
+ createListeners(parent);
+ }
+
+ private void createListeners(final Composite parent) {
+ /**
+ * Ideally not required. However the table viewer is not getting laid out properly on performing
+ * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window
+ */
+ addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(PaintEvent e) {
+ parent.layout();
+ }
+ });
+
+ clusterListener = createClusterListener();
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ toolkit.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+ });
+ }
+
+ protected abstract ClusterListener createClusterListener();
+ protected abstract IBaseLabelProvider getLabelProvider();
+ protected abstract IContentProvider getContentProvider();
+
+ private void createTreeViewer(List<Disk> allDisks, Composite tableViewerComposite) {
+ treeViewer = new TreeViewer(tableViewerComposite);
+ treeViewer.getTree().setHeaderVisible(true);
+ treeViewer.getTree().setLinesVisible(true);
+
+ TreeColumnLayout ad = new TreeColumnLayout();
+ tableViewerComposite.setLayout(ad);
+
+ TreeColumn column = new TreeColumn(treeViewer.getTree(),SWT.NONE);
+ column.setWidth(100);
+ column.setText("Disk");
+ ad.setColumnData(column, new ColumnWeightData(50, 100));
+
+ column = new TreeColumn(treeViewer.getTree(),SWT.NONE);
+ column.setWidth(100);
+ column.setText("Partition");
+ ad.setColumnData(column,new ColumnWeightData(50, 100));
+
+ column = new TreeColumn(treeViewer.getTree(),SWT.NONE);
+ column.setWidth(100);
+ column.setText("Free Space (GB)");
+ ad.setColumnData(column, new ColumnWeightData(50, 100));
+
+ column = new TreeColumn(treeViewer.getTree(),SWT.NONE);
+ column.setWidth(100);
+ column.setText("Total Space (GB)");
+ ad.setColumnData(column,new ColumnWeightData(50, 100));
+
+ column = new TreeColumn(treeViewer.getTree(),SWT.NONE);
+ column.setWidth(100);
+ column.setText("Status");
+ ad.setColumnData(column,new ColumnWeightData(50, 100));
+
+ treeViewer.setLabelProvider(getLabelProvider());
+ treeViewer.setContentProvider(getContentProvider());
+ treeViewer.setInput(allDisks);
+
+ // Create a case insensitive filter for the table viewer using the filter text field
+ guiHelper.createFilter(treeViewer, filterText, false);
+
+ treeViewer.expandAll();
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableViewerPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableViewerPage.java
new file mode 100644
index 00000000..88468eb3
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/AbstractTableViewerPage.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Hyperlink;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.console.utils.TableViewerComparator;
+import org.gluster.storage.management.core.model.ClusterListener;
+
+
+public abstract class AbstractTableViewerPage<T> extends Composite implements ISelectionListener {
+
+ private boolean useCheckboxes;
+ private boolean multiSelection;
+
+ protected final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ protected TableViewer tableViewer;
+ protected GUIHelper guiHelper = GUIHelper.getInstance();
+ protected Composite parent;
+ protected IWorkbenchSite site;
+
+ private Hyperlink linkAll, linkNone;
+ private ClusterListener clusterListener;
+
+ public AbstractTableViewerPage(IWorkbenchSite site, final Composite parent, int style, boolean useChechboxes, boolean multiSelection, Object model) {
+ super(parent, style);
+ this.parent = parent;
+ this.site = site;
+
+ this.useCheckboxes = useChechboxes;
+ this.multiSelection = multiSelection;
+
+ toolkit.adapt(this);
+ toolkit.paintBordersFor(this);
+
+ setupPageLayout();
+
+ createCheckboxSelectionLinks();
+
+ Text filterText = guiHelper.createFilterText(toolkit, this);
+
+ setupTableViewer(site, filterText);
+ tableViewer.setInput(model);
+ // register as selection provider so that other views can listen to any selection events on the tree
+ site.setSelectionProvider(tableViewer);
+ site.getPage().addSelectionListener(this);
+
+
+ parent.layout(); // Important - this actually paints the table
+
+ createListeners(parent);
+ }
+
+ public void createCheckboxSelectionLinks() {
+ if (useCheckboxes) {
+ // create the "select all/none" links
+ toolkit.createLabel(this, "Select");
+ linkAll = toolkit.createHyperlink(this, "all", SWT.NONE);
+ linkAll.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) {
+ ((CheckboxTableViewer) tableViewer).setAllChecked(true);
+ tableViewer.setSelection(new StructuredSelection(getAllEntities()));
+ }
+ });
+
+ toolkit.createLabel(this, " / ");
+
+ linkNone = toolkit.createHyperlink(this, "none", SWT.NONE);
+ linkNone.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) {
+ ((CheckboxTableViewer) tableViewer).setAllChecked(false);
+ tableViewer.setSelection(StructuredSelection.EMPTY);
+ }
+ });
+ } else {
+ // create dummy labels to maintain layout
+ toolkit.createLabel(this, "");
+ toolkit.createLabel(this, "");
+ toolkit.createLabel(this, "");
+ toolkit.createLabel(this, "");
+ }
+ }
+
+ private void createListeners(final Composite parent) {
+ /**
+ * Ideally not required. However the table viewer is not getting laid out properly on performing
+ * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window
+ */
+ addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(PaintEvent e) {
+ parent.layout();
+ }
+ });
+
+ clusterListener = createClusterListener();
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ toolkit.dispose();
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+ });
+ }
+
+ protected abstract ClusterListener createClusterListener();
+ protected abstract String[] getColumnNames();
+ protected abstract void setColumnProperties(Table table);
+ protected abstract IBaseLabelProvider getLabelProvider();
+ protected abstract IContentProvider getContentProvider();
+ protected abstract List<T> getAllEntities();
+
+ public void addDoubleClickListener(IDoubleClickListener listener) {
+ tableViewer.addDoubleClickListener(listener);
+ }
+
+ private void setupPageLayout() {
+ final GridLayout layout = new GridLayout(5, false);
+ layout.verticalSpacing = 10;
+ layout.marginTop = 10;
+ setLayout(layout);
+ }
+
+ protected void setupTable(Composite parent, Table table) {
+ table.setHeaderVisible(true);
+ table.setLinesVisible(false);
+
+ TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, getColumnNames());
+ parent.setLayout(tableColumnLayout);
+
+ setColumnProperties(table);
+ }
+
+ private void createTableViewer(Composite parent) {
+ int style = SWT.FLAT | SWT.FULL_SELECTION;
+ style |= (multiSelection ? SWT.MULTI : SWT.SINGLE);
+
+ if(useCheckboxes) {
+ tableViewer = CheckboxTableViewer.newCheckList(parent, style);
+ } else {
+ tableViewer = new TableViewer(parent, style);
+ }
+
+ tableViewer.setLabelProvider(getLabelProvider());
+ tableViewer.setContentProvider(getContentProvider());
+ setupTable(parent, tableViewer.getTable());
+ }
+
+ private Composite createTableViewerComposite() {
+ Composite tableViewerComposite = new Composite(this, SWT.NO);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ tableViewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ GridData layoutData = new GridData();
+ layoutData.horizontalSpan=5;
+ layoutData.grabExcessHorizontalSpace = true;
+ layoutData.horizontalAlignment = SWT.FILL;
+ layoutData.verticalAlignment = SWT.FILL;
+ layoutData.grabExcessVerticalSpace = true;
+ tableViewerComposite.setLayoutData(layoutData);
+
+ return tableViewerComposite;
+ }
+
+ private void setupTableViewer(IWorkbenchSite site, final Text filterText) {
+ Composite tableViewerComposite = createTableViewerComposite();
+ createTableViewer(tableViewerComposite);
+ site.setSelectionProvider(tableViewer);
+
+ if(useCheckboxes) {
+ // make sure that table selection is driven by checkbox selection
+ guiHelper.configureCheckboxTableViewer((CheckboxTableViewer)tableViewer);
+ }
+
+ // Create a case insensitive filter for the table viewer using the filter text field
+ guiHelper.createFilter(tableViewer, filterText, false);
+
+ tableViewer.setComparator(createViewerComparator());
+ for (int columnIndex = 0; columnIndex < tableViewer.getTable().getColumnCount(); columnIndex++) {
+ TableColumn column = tableViewer.getTable().getColumn(columnIndex);
+ column.addSelectionListener(getColumnSelectionAdapter(column, columnIndex));
+ }
+ }
+
+ private SelectionAdapter getColumnSelectionAdapter(final TableColumn column, final int columnIndex) {
+ return new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ViewerComparator viewerComparator = tableViewer.getComparator();
+ if(viewerComparator instanceof TableViewerComparator) {
+ TableViewerComparator comparator = (TableViewerComparator)viewerComparator;
+ comparator.setColumn(columnIndex);
+ tableViewer.getTable().setSortDirection(comparator.getDirection());
+ tableViewer.getTable().setSortColumn(column);
+ tableViewer.refresh();
+ }
+ }
+ };
+ }
+
+ protected abstract ViewerComparator createViewerComparator();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/BricksPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/BricksPage.java
new file mode 100644
index 00000000..c9660a77
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/BricksPage.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.BrickTableLabelProvider;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class BricksPage extends AbstractTableViewerPage<Brick> {
+ private List<Brick> bricks;
+
+ public enum BRICK_TABLE_COLUMN_INDICES {
+ SERVER, BRICK, FREE_SPACE, TOTAL_SPACE, STATUS
+ };
+
+ private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Server", "Brick Directory", "Free Space (GB)",
+ "Total Space (GB)", "Status" };
+
+ public BricksPage(Composite parent, int style, IWorkbenchSite site, final List<Brick> bricks) {
+ super(site, parent, style, true, true, bricks);
+ this.bricks = bricks;
+ }
+
+ @Override
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ switch (event.getEventType()) {
+ case BRICKS_ADDED:
+ tableViewer.add(((Collection<Brick>) event.getEventData()).toArray());
+ parent.update();
+ break;
+
+ case BRICKS_REMOVED:
+ tableViewer.remove(((Collection<Brick>) event.getEventData()).toArray());
+ parent.update();
+ break;
+
+ case BRICKS_CHANGED:
+ Object eventData = event.getEventData();
+ Brick[] updatedBricks;
+ if(eventData instanceof Map) {
+ updatedBricks = ((Map<Brick, Brick>) eventData).keySet().toArray(new Brick[0]);
+ } else {
+ updatedBricks = ((Collection<Brick>)eventData).toArray(new Brick[0]);
+ }
+ tableViewer.update(updatedBricks, null);
+ parent.update();
+ tableViewer.refresh(true);
+ default:
+ break;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected String[] getColumnNames() {
+ return DISK_TABLE_COLUMN_NAMES;
+ }
+
+ @Override
+ protected void setColumnProperties(Table table) {
+ guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.SERVER.ordinal(), SWT.CENTER, 100);
+ guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.BRICK.ordinal(), SWT.CENTER, 100);
+ guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.FREE_SPACE.ordinal(), SWT.CENTER, 90);
+ guiHelper.setColumnProperties(table, BRICK_TABLE_COLUMN_INDICES.TOTAL_SPACE.ordinal(), SWT.CENTER, 90);
+ }
+
+ @Override
+ protected ITableLabelProvider getLabelProvider() {
+ return new BrickTableLabelProvider();
+ }
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new ArrayContentProvider();
+ }
+
+ @Override
+ protected List<Brick> getAllEntities() {
+ return bricks;
+ }
+
+ @Override
+ protected ViewerComparator createViewerComparator() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DiskTreeContentProvider.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DiskTreeContentProvider.java
new file mode 100644
index 00000000..a7518d3c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DiskTreeContentProvider.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Partition;
+
+
+public class DiskTreeContentProvider implements ITreeContentProvider {
+
+ private List<Disk> disks = new ArrayList<Disk>();
+
+ public DiskTreeContentProvider(List<Disk> disks) {
+ this.disks = disks;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(Object inputElement) {
+ return ((List<Disk>) inputElement).toArray();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
+ */
+ public Object[] getChildren(Object parentElement) {
+ if(parentElement instanceof Disk) {
+ return ((Disk)parentElement).getPartitions().toArray();
+ } else {
+ return null;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
+ */
+ public Object getParent(Object element) {
+ if (element == null) {
+ return null;
+ }
+
+ if(element instanceof Partition) {
+ // find the disk of this partition and return
+ return getDiskForPartition((Partition)element);
+ } else {
+ return null;
+ }
+ }
+
+ private Disk getDiskForPartition(Partition partition) {
+ for(Disk disk : disks) {
+ for(Partition diskPartition : disk.getPartitions()) {
+ if(partition.getName().equals(diskPartition.getName())) {
+ return disk;
+ }
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
+ */
+ public boolean hasChildren(Object element) {
+ return (element instanceof Disk && ((Disk)element).getPartitions().size() > 0);
+ }
+
+
+
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DisksPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DisksPage.java
new file mode 100644
index 00000000..21704d4c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/DisksPage.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.DeviceTableLabelProvider;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Entity;
+
+
+public class DisksPage extends AbstractDisksPage {
+
+ public enum DISK_TABLE_COLUMN_INDICES {
+ DISK, PARTITION, FREE_SPACE, TOTAL_SPACE, STATUS
+ };
+
+ private static final String[] DISK_TABLE_COLUMN_NAMES = new String[] { "Disk", "Partition", "Free Space (GB)",
+ "Total Space (GB)", "Status" };
+
+ public DisksPage(final Composite parent, int style, IWorkbenchSite site, List<Disk> disks) {
+ super(parent, style, site, disks);
+ }
+
+ private String getDiskTableColumnDesc(DISK_TABLE_COLUMN_INDICES idx) {
+ return DISK_TABLE_COLUMN_NAMES[idx.ordinal()];
+ }
+
+ @Override
+ protected DeviceTableLabelProvider getLabelProvider() {
+ return new DeviceTableLabelProvider();
+ }
+
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new DiskTreeContentProvider(disks);
+ }
+
+ @Override
+ protected int getStatusColumnIndex() {
+ return DISK_TABLE_COLUMN_INDICES.STATUS.ordinal();
+ }
+
+ @Override
+ public void entityChanged(Entity entity, String[] paremeters) {
+ // TODO Auto-generated method stub
+
+ }
+
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/GlusterServersPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/GlusterServersPage.java
new file mode 100644
index 00000000..bf0e797d
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/GlusterServersPage.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.EntityGroupContentProvider;
+import org.gluster.storage.management.console.GlusterServerTableLabelProvider;
+import org.gluster.storage.management.console.utils.TableViewerComparator;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class GlusterServersPage extends AbstractTableViewerPage<GlusterServer> {
+ private List<GlusterServer> glusterServers;
+
+ public enum GLUSTER_SERVER_TABLE_COLUMN_INDICES {
+ NAME, IP_ADDRESSES, NUM_OF_CPUS, TOTAL_MEMORY, TOTAL_FREE_SPACE, TOTAL_DISK_SPACE, STATUS // Removed PREFERRED_NETWORK
+ };
+
+ private static final String[] GLUSTER_SERVER_TABLE_COLUMN_NAMES = new String[] { "Name", "IP Address(es)",
+ "Number" + CoreConstants.NEWLINE + "of CPUs", "Total" + CoreConstants.NEWLINE + "Memory (GB)",
+ "Free Space (GB)", "Total " + CoreConstants.NEWLINE + " Space (GB)", "Status" }; // Removed "Preferred\nNetwork",
+
+ public GlusterServersPage(IWorkbenchSite site, final Composite parent, int style, final EntityGroup<GlusterServer> servers) {
+ super(site, parent, style, true, true, servers);
+ this.glusterServers = servers.getEntities();
+ }
+
+ @Override
+ protected ViewerComparator createViewerComparator() {
+ return new TableViewerComparator();
+ }
+
+ @Override
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+
+ @Override
+ public void serverAdded(GlusterServer server) {
+ tableViewer.add(server);
+ parent.update();
+ }
+
+ @Override
+ public void serverRemoved(GlusterServer server) {
+ tableViewer.remove(server);
+ parent.update();
+ }
+
+ @Override
+ public void serverChanged(GlusterServer server, Event event) {
+ tableViewer.update(server, null);
+ parent.update();
+ }
+ };
+ }
+
+ @Override
+ protected void setColumnProperties(Table table) {
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NAME, SWT.CENTER, 100);
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.STATUS, SWT.CENTER, 70);
+ // setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.PREFERRED_NETWORK, SWT.CENTER, 90);
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.NUM_OF_CPUS, SWT.CENTER, 90);
+ //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.CPU_USAGE, SWT.CENTER, 90);
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_MEMORY, SWT.CENTER, 90);
+ //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE, SWT.CENTER, 90);
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_FREE_SPACE, SWT.CENTER, 90);
+ setColumnProperties(table, GLUSTER_SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE, SWT.CENTER, 90);
+ //setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90);
+ }
+
+ @Override
+ protected IBaseLabelProvider getLabelProvider() {
+ return new GlusterServerTableLabelProvider();
+ }
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new EntityGroupContentProvider<GlusterServer>();
+ }
+
+ @Override
+ protected String[] getColumnNames() {
+ return GLUSTER_SERVER_TABLE_COLUMN_NAMES;
+ }
+
+ @Override
+ protected List<GlusterServer> getAllEntities() {
+ return glusterServers;
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ public void setColumnProperties(Table table, GLUSTER_SERVER_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionKeyEditingSupport.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionKeyEditingSupport.java
new file mode 100644
index 00000000..676e0ee4
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionKeyEditingSupport.java
@@ -0,0 +1,120 @@
+/**
+ *
+ */
+package org.gluster.storage.management.console.views.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeOption;
+import org.gluster.storage.management.core.model.VolumeOptionInfo;
+import org.gluster.storage.management.core.model.VolumeOptions;
+
+
+/**
+ * Editing support for the "value" column in volume options table viewer.
+ */
+public class OptionKeyEditingSupport extends EditingSupport {
+ private CellEditor cellEditor;
+ private Volume volume;
+ private List<VolumeOptionInfo> defaults = GlusterDataModelManager.getInstance().getVolumeOptionsInfo();
+ private String[] allowedKeys;
+ private ColumnViewer viewer;
+
+ public OptionKeyEditingSupport(ColumnViewer viewer, Volume volume) {
+ super(viewer);
+ this.volume = volume;
+ this.viewer = viewer;
+ }
+
+ /**
+ * @return array of option keys that are not already set on the volume
+ */
+ private String[] getAllowedKeys() {
+ ArrayList<String> keys = new ArrayList<String>();
+ VolumeOptions volumeOptions = volume.getOptions();
+ for(VolumeOptionInfo optionInfo : defaults) {
+ String optionName = optionInfo.getName();
+ if(!volumeOptions.containsKey(optionName) || volumeOptions.get(optionName).isEmpty()) {
+ // key not set => available for setting
+ // value not set => this is the row being edited
+ keys.add(optionName);
+ }
+ }
+ return keys.toArray(new String[0]);
+ }
+
+ @Override
+ protected void setValue(final Object element, final Object value) {
+ VolumeOption oldEntry = (VolumeOption)element;
+ Integer newValue = (Integer)value;
+ String newKey = allowedKeys[newValue];
+
+ if (((VolumeOption)element).getKey().equals(newKey)) {
+ // selected value is same as old one.
+ return;
+ }
+
+ // value has changed. set new value and refresh the viewer.
+ volume.getOptions().remove(oldEntry.getKey());
+ volume.setOption(newKey, "");
+ getViewer().refresh();
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ VolumeOption entryBeingAdded = getEntryBeingAdded();
+ if(entryBeingAdded == null) {
+ return cellEditor.getValue();
+ }
+
+ if(entryBeingAdded.getKey().isEmpty()) {
+ // editing just about to start. set first element as default.
+ return 0;
+ }
+
+ return getIndexOfEntry(entryBeingAdded);
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ allowedKeys = getAllowedKeys();
+ cellEditor = new ComboBoxCellEditor((Composite) viewer.getControl(), allowedKeys, SWT.READ_ONLY);
+ return cellEditor;
+ }
+
+ private int getIndexOfEntry(VolumeOption entryBeingAdded) {
+ for(int index = 0; index < allowedKeys.length; index++) {
+ if(allowedKeys[index].equals(entryBeingAdded.getKey())) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ protected VolumeOption getEntryBeingAdded() {
+ List<VolumeOption> options = volume.getOptions().getOptions();
+ int size = options.size();
+ String lastValue = options.get(size - 1).getValue();
+ if(lastValue == null || lastValue.isEmpty()) {
+ // it's the LAST entry, and it's value is empty.
+ // means this is a new row being added in the table viewer.
+ return options.get(size - 1);
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ VolumeOption entry = (VolumeOption)element;
+ return (entry.getKey().isEmpty() || entry.getValue().isEmpty());
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionValueEditingSupport.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionValueEditingSupport.java
new file mode 100644
index 00000000..b2493f0f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/OptionValueEditingSupport.java
@@ -0,0 +1,110 @@
+/**
+ *
+ */
+package org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeOption;
+import org.gluster.storage.management.core.model.VolumeOptionInfo;
+
+
+/**
+ * Editing support for the "value" column in volume options table viewer.
+ */
+public class OptionValueEditingSupport extends EditingSupport {
+ private CellEditor cellEditor;
+ private Volume volume;
+ private List<VolumeOptionInfo> defaults = GlusterDataModelManager.getInstance().getVolumeOptionsInfo();
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+
+ public OptionValueEditingSupport(ColumnViewer viewer, Volume volume) {
+ super(viewer);
+ this.volume = volume;
+ this.cellEditor = new TextCellEditor((Composite) viewer.getControl());
+ }
+
+ @Override
+ protected void setValue(final Object element, final Object value) {
+ final VolumeOption entry = (VolumeOption)element;
+ final String optionKey = entry.getKey();
+ final String optionValue = (String)value;
+ final String oldValue = entry.getValue();
+
+ // It is not allowed to change value to empty string
+ if(optionValue.isEmpty()) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option",
+ "Option value can't be empty! Please enter a valid value.");
+ cellEditor.setFocus();
+ return;
+ }
+
+ if (oldValue.equals(optionValue)) {
+ // value is same as that present in the model. return without doing anything.
+ return;
+ }
+
+ // value has changed. set volume option at back-end and update model accordingly
+ guiHelper.setStatusMessage("Setting option [" + optionKey + " = " + optionValue + "]...");
+ getViewer().getControl().update();
+
+ BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
+
+ @Override
+ public void run() {
+ VolumesClient client = new VolumesClient();
+ try {
+ client.setVolumeOption(volume.getName(), optionKey, optionValue);
+ GlusterDataModelManager.getInstance().setVolumeOption(volume, optionKey, optionValue);
+ } catch(Exception e) {
+ MessageDialog.openError(Display.getDefault().getActiveShell(), "Set Volume Option", e.getMessage());
+ }
+ getViewer().update(entry, null);
+ }
+ });
+
+ guiHelper.clearStatusMessage();
+ getViewer().getControl().update();
+ }
+
+ /**
+ * @param key Key whose default value is to be fetched
+ * @return Default value of the volume option with given key
+ */
+ private String getDefaultValue(String key) {
+ for(VolumeOptionInfo optionInfo : defaults) {
+ if(optionInfo.getName().equals(key)) {
+ return optionInfo.getDefaultValue();
+ }
+ }
+ return "";
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ VolumeOption entry = (VolumeOption) element;
+ return entry.getValue().isEmpty() ? getDefaultValue(entry.getKey()) : entry.getValue();
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return cellEditor;
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ return true;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerDisksPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerDisksPage.java
new file mode 100644
index 00000000..da25e49f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerDisksPage.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.ServerDiskTableLabelProvider;
+import org.gluster.storage.management.core.model.Disk;
+import org.gluster.storage.management.core.model.Entity;
+
+
+public class ServerDisksPage extends AbstractDisksPage {
+
+ public ServerDisksPage(Composite parent, int style, IWorkbenchSite site, List<Disk> disks) {
+ super(parent, style, site, disks);
+ }
+
+ public enum SERVER_DISK_TABLE_COLUMN_INDICES {
+ DISK, PARTITION, FREE_SPACE, TOTAL_SPACE, STATUS
+ };
+
+ private static final String[] SERVER_DISK_TABLE_COLUMN_NAMES = new String[] { "Disk", "Partition", "Free Space (GB)",
+ "Total Space (GB)", "Status" };
+
+ @Override
+ protected int getStatusColumnIndex() {
+ return SERVER_DISK_TABLE_COLUMN_INDICES.STATUS.ordinal();
+ }
+
+ @Override
+ protected ServerDiskTableLabelProvider getLabelProvider() {
+ // return new DeviceTableLabelProvider();
+ return new ServerDiskTableLabelProvider();
+ }
+
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new DiskTreeContentProvider(disks);
+ }
+
+ @Override
+ public void entityChanged(Entity entity, String[] paremeters) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerLogsPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerLogsPage.java
new file mode 100644
index 00000000..ec7c65c6
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServerLogsPage.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.model.GlusterServer;
+
+
+public class ServerLogsPage extends Composite {
+
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Text text;
+ private Table table;
+
+ public enum LOG_TABLE_COLUMN_INDICES {
+ DATE, TIME, DISK, SEVERITY, MESSAGE
+ };
+
+ private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Disk", "Severity", "Message" };
+
+ /**
+ * Create the composite.
+ *
+ * @param parent
+ * @param style
+ */
+ public ServerLogsPage(Composite parent, int style, GlusterServer server) {
+ super(parent, style);
+ addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ toolkit.dispose();
+ }
+ });
+ toolkit.adapt(this);
+ toolkit.paintBordersFor(this);
+
+ setLayout(new GridLayout(1, false));
+ GridData layoutData = new GridData();
+ layoutData.grabExcessHorizontalSpace = true;
+ layoutData.grabExcessVerticalSpace = true;
+ setLayoutData(layoutData);
+
+ Composite composite = toolkit.createComposite(this, SWT.NONE);
+ toolkit.paintBordersFor(composite);
+
+ Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE);
+ lblScanLast.setBounds(0, 15, 80, 20);
+
+ text = toolkit.createText(composite, "100", SWT.NONE);
+ text.setBounds(85, 15, 60, 20);
+ text.setTextLimit(4);
+ text.addVerifyListener(new VerifyListener() {
+
+ @Override
+ public void verifyText(VerifyEvent event) {
+ // Assume we allow it
+ event.doit = true;
+
+ String text = event.text;
+ char[] chars = text.toCharArray();
+
+ // Don't allow if text contains non-digit characters
+ for (int i = 0; i < chars.length; i++) {
+ if (!Character.isDigit(chars[i])) {
+ event.doit = false;
+ break;
+ }
+ }
+
+ }
+ });
+
+ Label lblMessagesAndFilter = toolkit.createLabel(composite, " messages from ", SWT.CENTER);
+ lblMessagesAndFilter.setBounds(160, 15, 110, 20);
+
+ Combo combo = new Combo(composite, SWT.CENTER);
+ combo.setBounds(295, 15, 100, 20);
+ combo.setItems(new String[] { "syslog", "dmesg" });
+ toolkit.adapt(combo);
+ toolkit.paintBordersFor(combo);
+ combo.select(0);
+
+ Button btngo = toolkit.createButton(composite, "&Go", SWT.NONE);
+ btngo.setBounds(410, 13, 50, 30);
+
+ Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL);
+ separator.setBounds(0, 50, 500, 2);
+
+ Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT);
+ lblFilterString.setBounds(0, 65, 100, 20);
+
+ text = guiHelper.createFilterText(toolkit, composite);
+ text.setBounds(105, 65, 250, 20);
+
+ Composite logContentsComposite = createLogContentsComposite(toolkit);
+ // Text logContentsText = toolkit.createText(logContentsComposite, "", SWT.MULTI | SWT.FLAT | SWT.BORDER);
+ // logContentsText.setEditable(false);
+ // populateDummyLogContent(logContentsText);
+
+ ListViewer logViewer = new ListViewer(logContentsComposite, SWT.BORDER | SWT.V_SCROLL | SWT.NO);
+ logViewer.setContentProvider(new ArrayContentProvider());
+ guiHelper.createFilter(logViewer, text, false);
+ logViewer.setInput(getDummyLogContents());
+
+ // TODO: Link the filter string with the contents text
+ }
+
+ private Composite createLogContentsComposite(FormToolkit toolkit) {
+ Composite tableViewerComposite = toolkit.createComposite(this, SWT.NONE);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.verticalIndent = 10;
+ tableViewerComposite.setLayoutData(layoutData);
+ return tableViewerComposite;
+ }
+
+ private String[] getDummyLogContents() {
+
+ String[] logMessages = {
+ "Jan 19 13:43:08 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:44:08 shireesh-laptop dhclient: last message repeated 5 times",
+ "Jan 19 13:44:47 shireesh-laptop dhclient: last message repeated 2 times",
+ "Jan 19 13:44:47 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67",
+ "Jan 19 13:45:49 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:46:59 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:48:01 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:49:02 shireesh-laptop dhclient: last message repeated 5 times",
+ "Jan 19 13:50:08 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:51:08 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:52:08 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:53:08 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:54:08 shireesh-laptop dhclient: last message repeated 5 times",
+ "Jan 19 13:55:08 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:56:08 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:57:08 shireesh-laptop dhclient: last message repeated 3 times",
+ "Jan 19 13:58:08 shireesh-laptop dhclient: last message repeated 6 times",
+ "Jan 19 13:59:08 shireesh-laptop dhclient: last message repeated 4 times",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: last message repeated 3 times",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> DHCP: device eth1 state changed bound -> expire",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPDISCOVER on eth1 to 255.255.255.255 port 67 interval 8",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> DHCP: device eth1 state changed expire -> preinit",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPOFFER of 192.168.1.174 from 192.168.1.1",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPREQUEST of 192.168.1.174 on eth1 to 255.255.255.255 port 67",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: DHCPACK of 192.168.1.174 from 192.168.1.1",
+ "Jan 19 13:59:40 shireesh-laptop dhclient: bound to 192.168.1.174 -- renewal in 3205 seconds.",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> DHCP: device eth1 state changed preinit -> bound",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> address 192.168.1.174",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> prefix 24 (255.255.255.0)",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> gateway 192.168.1.1",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> nameserver '192.168.1.1'",
+ "Jan 19 13:59:40 shireesh-laptop NetworkManager: <info> domain name 'in.gluster.com'",
+ "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.",
+ "Jan 19 14:03:53 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'",
+ "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.",
+ "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Invalid legacy unicast query packet.",
+ "Jan 19 14:03:54 shireesh-laptop avahi-daemon[1098]: Received response from host 192.168.1.155 with invalid source port 37219 on interface 'eth0.0'",
+ "Jan 19 14:05:09 shireesh-laptop avahi-daemon[1098]: last message repeated 8 times",
+ "Jan 19 14:12:48 shireesh-laptop NetworkManager: <debug> [1295426568.002642] periodic_update(): Roamed from BSSID E0:CB:4E:C0:0B:7F (glfs) to (none) ((none))",
+ "Jan 19 14:12:54 shireesh-laptop NetworkManager: <debug> [1295426574.002448] periodic_update(): Roamed from BSSID (none) ((none)) to E0:CB:4E:C0:0B:7F (glfs)",
+ "Jan 19 14:17:01 shireesh-laptop CRON[5321]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly)" };
+
+ return logMessages;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServersPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServersPage.java
new file mode 100644
index 00000000..ae34e948
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/ServersPage.java
@@ -0,0 +1,138 @@
+ /*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.EntityGroupContentProvider;
+import org.gluster.storage.management.console.ServerTableLabelProvider;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.Server;
+
+
+public class ServersPage extends AbstractTableViewerPage<Server> {
+ private List<Server> servers;
+
+ public enum SERVER_TABLE_COLUMN_INDICES {
+ NAME, IP_ADDRESSES, NUM_OF_DISKS, TOTAL_DISK_SPACE
+ };
+
+ private static final String[] SERVER_TABLE_COLUMN_NAMES = new String[] { "Name", "IP Address(es)", "Number of Disks", "Total Disk Space (GB)" };
+
+ public ServersPage(final Composite parent, IWorkbenchSite site, EntityGroup<Server> serversGroup) {
+ super(site, parent, SWT.NONE, true, true, serversGroup);
+ this.servers = serversGroup.getEntities();
+ }
+
+ @Override
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+ @Override
+ public void discoveredServerRemoved(Server server) {
+ tableViewer.remove(server);
+ parent.update();
+ }
+
+ @Override
+ public void discoveredServerAdded(Server server) {
+ tableViewer.add(server);
+ parent.update();
+ }
+
+ @Override
+ public void discoveredServerChanged(Server server, Event event) {
+ tableViewer.update(server, null);
+ parent.update();
+ }
+ };
+ }
+
+ public void setInput(EntityGroup<Server> servers) {
+ tableViewer.setInput(servers);
+ tableViewer.refresh();
+ }
+
+ @Override
+ protected void setColumnProperties(Table table) {
+ setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.NAME, SWT.CENTER, 70);
+ setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.IP_ADDRESSES, SWT.CENTER, 100);
+ setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.NUM_OF_DISKS, SWT.CENTER, 70);
+ setColumnProperties(table, SERVER_TABLE_COLUMN_INDICES.TOTAL_DISK_SPACE, SWT.CENTER, 70);
+ // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.NUM_OF_CPUS, SWT.CENTER, 90);
+ // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.CPU_USAGE, SWT.CENTER, 90);
+ // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.TOTAL_MEMORY, SWT.CENTER, 90);
+ // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.MEMORY_IN_USE, SWT.CENTER, 90);
+ // setColumnProperties(table, SERVER_DISK_TABLE_COLUMN_INDICES.DISK_SPACE_IN_USE, SWT.CENTER, 90);
+ }
+
+ @Override
+ protected String[] getColumnNames() {
+ return SERVER_TABLE_COLUMN_NAMES;
+ }
+
+ @Override
+ protected IBaseLabelProvider getLabelProvider() {
+ return new ServerTableLabelProvider();
+ }
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new EntityGroupContentProvider<Server>();
+ }
+
+ @Override
+ protected List<Server> getAllEntities() {
+ return servers;
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ private void setColumnProperties(Table table, SERVER_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ @Override
+ protected ViewerComparator createViewerComparator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/TasksPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/TasksPage.java
new file mode 100644
index 00000000..aeea018c
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/TasksPage.java
@@ -0,0 +1,151 @@
+/**
+ * TasksPage.java
+ *
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.TasksTableLabelProvider;
+import org.gluster.storage.management.console.toolbar.GlusterToolbarManager;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Entity;
+import org.gluster.storage.management.core.model.TaskInfo;
+
+
+public class TasksPage extends AbstractTableViewerPage<TaskInfo> {
+ private List<TaskInfo> taskInfoList;
+ private TaskInfo selectedTask;
+
+ public enum TASK_TABLE_COLUMN_INDICES {
+ TASK, STATUS
+ };
+
+ private static final String[] TASK_TABLE_COLUMN_NAMES = new String[] { "Task", "Status"};
+
+
+ public TasksPage(IWorkbenchSite site, Composite parent, int style, List<TaskInfo> taskInfo) {
+ super(site, parent, style, false, false, taskInfo);
+ this.taskInfoList = taskInfo;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#createClusterListener()
+ */
+ @Override
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+ @Override
+ public void taskAdded(TaskInfo taskInfo) {
+ tableViewer.add(taskInfo);
+ parent.update();
+ }
+
+ @Override
+ public void taskRemoved(TaskInfo taskInfo) {
+ tableViewer.remove(taskInfo);
+ parent.update();
+ // hide the task related actionset as no task is selected
+ // site.getPage().hideActionSet(ActionConstants.ACTION_SET_TASK);
+ }
+
+ @Override
+ public void taskUpdated(TaskInfo taskInfo) {
+ tableViewer.update(taskInfo, null);
+ parent.update();
+ // fire selection event so that toolbar gets updated
+ // (the action class listens to selection and enables/disables automatically)
+ tableViewer.setSelection(new StructuredSelection(taskInfo));
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#getColumnNames()
+ */
+ @Override
+ protected String[] getColumnNames() {
+ return TASK_TABLE_COLUMN_NAMES;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#setColumnProperties(org.eclipse.swt.widgets.Table)
+ */
+ @Override
+ protected void setColumnProperties(Table table) {
+ guiHelper.setColumnProperties(table, TASK_TABLE_COLUMN_INDICES.TASK.ordinal(), SWT.LEFT, 50);
+ guiHelper.setColumnProperties(table, TASK_TABLE_COLUMN_INDICES.STATUS.ordinal(), SWT.LEFT, 50);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#getLabelProvider()
+ */
+ @Override
+ protected IBaseLabelProvider getLabelProvider() {
+ return new TasksTableLabelProvider();
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#getContentProvider()
+ */
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new ArrayContentProvider();
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#getAllEntities()
+ */
+ @Override
+ protected List<TaskInfo> getAllEntities() {
+ return taskInfoList;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.console.views.pages.AbstractTableViewerPage#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (selection instanceof StructuredSelection) {
+ Entity selectedEntity = (Entity) ((StructuredSelection) selection).getFirstElement();
+ if (selectedEntity != null && selectedEntity instanceof TaskInfo && selectedEntity != selectedTask) {
+ selectedTask = (TaskInfo)selectedEntity;
+ new GlusterToolbarManager(part.getSite().getWorkbenchWindow()).updateToolbar(selectedTask);
+ }
+ }
+ }
+
+ @Override
+ protected ViewerComparator createViewerComparator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeLogsPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeLogsPage.java
new file mode 100644
index 00000000..d32589bb
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeLogsPage.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DateTime;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.gluster.storage.management.client.VolumesClient;
+import org.gluster.storage.management.console.VolumeLogTableLabelProvider;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants.VOLUME_LOG_LEVELS;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeLogMessage;
+
+
+public class VolumeLogsPage extends Composite {
+
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private final GUIHelper guiHelper = GUIHelper.getInstance();
+ private Text filterText;
+ private Text lineCountText;
+ private Volume volume;
+
+ public enum LOG_TABLE_COLUMN_INDICES {
+ DATE, TIME, BRICK, SEVERITY, MESSAGE
+ };
+
+ private static final String[] LOG_TABLE_COLUMN_NAMES = new String[] { "Date", "Time", "Brick", "Severity", "Message" };
+ private TableViewer tableViewer;
+ private Combo bricksCombo;
+ private Combo severityCombo;
+ private DateTime fromDate;
+ private DateTime fromTime;
+ private DateTime toDate;
+ private DateTime toTime;
+ private Button fromCheckbox;
+ private Button toCheckbox;
+
+ /**
+ * Create the volume logs page
+ *
+ * @param parent
+ * @param style
+ * @param volume
+ * Volume for which the logs page is to be created
+ */
+ public VolumeLogsPage(Composite parent, int style, Volume volume) {
+ super(parent, style);
+ this.volume = volume;
+
+ addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ toolkit.dispose();
+ }
+ });
+ toolkit.adapt(this);
+ toolkit.paintBordersFor(this);
+
+ configureLayout();
+
+ Composite composite = toolkit.createComposite(this, SWT.NONE);
+ toolkit.paintBordersFor(composite);
+
+ createLineCountLabel(composite);
+ createLineCountText(composite);
+
+ createBricksLabel(composite);
+ createBricksCombo(composite);
+
+ createSeverityLabel(composite);
+ createSeverityCombo(composite);
+
+ createFromDateLabel(composite);
+ createFromDateField(composite);
+ createFromTimeField(composite);
+ createFromCheckbox(composite);
+
+ createToDateLabel(composite);
+ createToDateField(composite);
+ createToTimeField(composite);
+ createToCheckbox(composite);
+
+ createSearchButton(composite);
+
+ createSeparator(composite);
+
+ createFilterLabel(composite);
+ createFilterText(composite);
+
+ createLogTableViewer();
+ }
+
+ private void createLogTableViewer() {
+ Composite tableViewerComposite = createTableViewerComposite();
+
+ tableViewer = new TableViewer(tableViewerComposite, SWT.FLAT | SWT.FULL_SELECTION | SWT.MULTI);
+ tableViewer.setLabelProvider(new VolumeLogTableLabelProvider());
+ tableViewer.setContentProvider(new ArrayContentProvider());
+
+ setupLogsTable(tableViewerComposite, tableViewer.getTable());
+ guiHelper.createFilter(tableViewer, filterText, false);
+ }
+
+ private void createFilterText(Composite composite) {
+ filterText = guiHelper.createFilterText(toolkit, composite);
+ filterText.setBounds(90, 105, 250, 20);
+ }
+
+ private void createFilterLabel(Composite composite) {
+ Label lblFilterString = toolkit.createLabel(composite, "Filter String", SWT.LEFT);
+ lblFilterString.setBounds(0, 105, 85, 20);
+ }
+
+ private void createSeparator(Composite composite) {
+ Label separator = toolkit.createLabel(composite, "", SWT.SEPARATOR | SWT.HORIZONTAL | SWT.FILL);
+ separator.setBounds(0, 95, 680, 2);
+ }
+
+ private void createSearchButton(Composite composite) {
+ Button btnGo = toolkit.createButton(composite, "&Fetch Logs", SWT.NONE);
+ btnGo.setBounds (615, 55, 75, 30);
+ btnGo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ VolumesClient client = new VolumesClient();
+
+ Date fromTimestamp = null;
+ Date toTimestamp = null;
+
+ if (fromCheckbox.getSelection()) {
+ fromTimestamp = extractTimestamp(fromDate, fromTime);
+ }
+
+ if (toCheckbox.getSelection()) {
+ toTimestamp = extractTimestamp(toDate, toTime);
+ }
+
+ if (!validateTimeRange(fromTimestamp, toTimestamp)) {
+ return;
+ }
+
+ try {
+ List<VolumeLogMessage> logMessages = client.getLogs(volume.getName(), bricksCombo.getText(),
+ severityCombo.getText(), fromTimestamp, toTimestamp,
+ Integer.parseInt(lineCountText.getText()));
+ tableViewer.setInput(logMessages.toArray(new VolumeLogMessage[0]));
+ tableViewer.refresh();
+ } catch (Exception ex) {
+ MessageDialog.openError(getShell(), "Volume Logs",
+ "Error while fetching volume logs: [" + ex.getMessage() + "]");
+ }
+ }
+ });
+ }
+
+ protected boolean validateTimeRange(Date fromTimestamp, Date toTimestamp) {
+ if (fromTimestamp == null && toTimestamp == null) {
+ // no time range selected. nothing to validate.
+ return true;
+ }
+
+ Calendar calendar = Calendar.getInstance();
+ Date now = calendar.getTime();
+ if (fromTimestamp != null && fromTimestamp.after(now)) {
+ MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than current time!");
+ return false;
+ }
+
+ if (toTimestamp != null) {
+ if (toTimestamp.after(now)) {
+ MessageDialog.openError(getShell(), "Volume Logs", "To time can't be greater than current time!");
+ return false;
+ }
+
+ if (fromTimestamp.after(toTimestamp)) {
+ MessageDialog.openError(getShell(), "Volume Logs", "From time can't be greater than To time!");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void createToCheckbox(Composite composite) {
+ toCheckbox = toolkit.createButton(composite, null, SWT.CHECK);
+ toCheckbox.setBounds(320, 60, 15, 20);
+ toCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (toCheckbox.getSelection()) {
+ toDate.setEnabled(true);
+ toTime.setEnabled(true);
+ } else {
+ toDate.setEnabled(false);
+ toTime.setEnabled(false);
+ }
+ }
+ });
+ }
+
+ private void createToTimeField(Composite composite) {
+ toTime = new DateTime(composite, SWT.BORDER | SWT.TIME);
+ toTime.setBounds(490, 60, 120, 20);
+ toTime.setEnabled(false);
+ toolkit.adapt(toTime);
+ toolkit.paintBordersFor(toTime);
+ }
+
+ private void createToDateField(Composite composite) {
+ toDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN);
+ toDate.setBounds(365, 60, 120, 20);
+ toDate.setEnabled(false);
+ toolkit.adapt(toDate);
+ toolkit.paintBordersFor(toDate);
+ }
+
+ private void createToDateLabel(Composite composite) {
+ Label lblTo = toolkit.createLabel(composite, "To", SWT.NONE);
+ lblTo.setBounds(340, 60, 25, 20);
+ }
+
+ private void createFromCheckbox(Composite composite) {
+ fromCheckbox = toolkit.createButton(composite, null, SWT.CHECK);
+ fromCheckbox.setBounds(0, 60, 15, 20);
+ fromCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fromCheckbox.getSelection()) {
+ fromDate.setEnabled(true);
+ fromTime.setEnabled(true);
+ } else {
+ fromDate.setEnabled(false);
+ fromTime.setEnabled(false);
+ }
+ }
+ });
+ }
+
+ private void createFromTimeField(Composite composite) {
+ fromTime = new DateTime(composite, SWT.BORDER | SWT.TIME);
+ fromTime.setBounds(190, 60, 120, 20);
+ fromTime.setEnabled(false);
+ toolkit.adapt(fromTime);
+ toolkit.paintBordersFor(fromTime);
+ }
+
+ private void createFromDateField(Composite composite) {
+ fromDate = new DateTime(composite, SWT.BORDER | SWT.DROP_DOWN);
+ fromDate.setBounds(60, 60, 120, 20);
+ fromDate.setEnabled(false);
+ toolkit.adapt(fromDate);
+ toolkit.paintBordersFor(fromDate);
+ }
+
+ private void createFromDateLabel(Composite composite) {
+ Label lblFrom = toolkit.createLabel(composite, "from", SWT.NONE);
+ lblFrom.setBounds(20, 60, 40, 20);
+ }
+
+ private void createSeverityCombo(Composite composite) {
+ severityCombo = new Combo(composite, SWT.READ_ONLY);
+ severityCombo.setBounds(555, 15, 110, 20);
+
+ severityCombo.setItems(GlusterConstants.VOLUME_LOG_LEVELS_ARR.toArray(new String[0]));
+ severityCombo.select(VOLUME_LOG_LEVELS.ERROR.ordinal());
+ severityCombo.add(CoreConstants.ALL, 0);
+
+ toolkit.adapt(severityCombo);
+ toolkit.paintBordersFor(severityCombo);
+ }
+
+ private void createSeverityLabel(Composite composite) {
+ Label lblSeverity = toolkit.createLabel(composite, "Severity", SWT.NONE);
+ lblSeverity.setBounds(480, 15, 70, 20);
+ }
+
+ private void createBricksCombo(Composite composite) {
+ bricksCombo = new Combo(composite, SWT.READ_ONLY);
+ bricksCombo.setBounds(365, 15, 100, 20);
+ bricksCombo.setItems( volume.getBrickDirectories().toArray(new String[0]));
+ bricksCombo.add(CoreConstants.ALL, 0);
+ toolkit.adapt(bricksCombo);
+ toolkit.paintBordersFor(bricksCombo);
+ bricksCombo.select(0);
+ }
+
+ private void createBricksLabel(Composite composite) {
+ Label lblMessagesAndFilter = toolkit.createLabel(composite, "messages, and filter on bricks", SWT.NONE);
+ lblMessagesAndFilter.setBounds(160, 15, 200, 20);
+ }
+
+ private void createLineCountText(Composite composite) {
+ lineCountText = toolkit.createText(composite, "100", SWT.NONE);
+ lineCountText.setBounds(85, 15, 60, 20);
+ lineCountText.setTextLimit(4);
+ lineCountText.addVerifyListener(new VerifyListener() {
+
+ @Override
+ public void verifyText(VerifyEvent event) {
+ // Assume we allow it
+ event.doit = true;
+
+ String text = event.text;
+ char[] chars = text.toCharArray();
+
+ // Don't allow if text contains non-digit characters
+ for (int i = 0; i < chars.length; i++) {
+ if (!Character.isDigit(chars[i])) {
+ event.doit = false;
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ private void createLineCountLabel(Composite composite) {
+ Label lblScanLast = toolkit.createLabel(composite, "Scan last", SWT.NONE);
+ lblScanLast.setBounds(0, 15, 80, 20);
+ }
+
+ private void configureLayout() {
+ setLayout(new GridLayout(1, false));
+ GridData layoutData = new GridData();
+ layoutData.grabExcessHorizontalSpace = true;
+ layoutData.grabExcessVerticalSpace = true;
+ // layoutData.verticalIndent = 10;
+ setLayoutData(layoutData);
+ }
+
+ private Composite createTableViewerComposite() {
+ Composite tableViewerComposite = new Composite(this, SWT.NO);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.verticalIndent = 10;
+ tableViewerComposite.setLayoutData(layoutData);
+ return tableViewerComposite;
+ }
+
+ private void setupLogsTable(Composite parent, Table table) {
+ table.setHeaderVisible(true);
+ table.setLinesVisible(false);
+
+ TableColumnLayout tableColumnLayout = guiHelper.createTableColumnLayout(table, LOG_TABLE_COLUMN_NAMES);
+ parent.setLayout(tableColumnLayout);
+
+ setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.DATE, SWT.CENTER, 50);
+ setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.TIME, SWT.CENTER, 50);
+ setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.BRICK, SWT.CENTER, 50);
+ setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.SEVERITY, SWT.CENTER, 50);
+ setColumnProperties(table, LOG_TABLE_COLUMN_INDICES.MESSAGE, SWT.LEFT, 100);
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ private void setColumnProperties(Table table, LOG_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ private Date extractTimestamp(DateTime date, DateTime time) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setLenient(false);
+ calendar.set(Calendar.DAY_OF_MONTH, date.getDay());
+ // in Calendar class, month starts with zero i.e. Jan = 0
+ calendar.set(Calendar.MONTH, date.getMonth());
+ calendar.set(Calendar.YEAR, date.getYear());
+ calendar.set(Calendar.HOUR_OF_DAY, time.getHours());
+ calendar.set(Calendar.MINUTE, time.getMinutes());
+ calendar.set(Calendar.SECOND, time.getSeconds());
+ return calendar.getTime();
+ }
+
+ public void addDoubleClickListener(IDoubleClickListener listener) {
+ tableViewer.addDoubleClickListener(listener);
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeOptionsPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeOptionsPage.java
new file mode 100644
index 00000000..4363b7e9
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumeOptionsPage.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.apache.commons.lang.WordUtils;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnLayoutData;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.gluster.storage.management.console.GlusterDataModelManager;
+import org.gluster.storage.management.console.VolumeOptionsContentProvider;
+import org.gluster.storage.management.console.VolumeOptionsTableLabelProvider;
+import org.gluster.storage.management.console.utils.GUIHelper;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeOption;
+import org.gluster.storage.management.core.model.VolumeOptionInfo;
+
+
+public class VolumeOptionsPage extends Composite {
+
+ private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
+ private TableViewer tableViewer;
+ private GUIHelper guiHelper = GUIHelper.getInstance();
+ private Volume volume;
+ private DefaultClusterListener clusterListener;
+ private Text filterText;
+ private List<VolumeOptionInfo> defaultVolumeOptions = GlusterDataModelManager.getInstance()
+ .getVolumeOptionsInfo();
+
+ public enum OPTIONS_TABLE_COLUMN_INDICES {
+ OPTION_KEY, OPTION_VALUE
+ };
+
+ private static final String[] OPTIONS_TABLE_COLUMN_NAMES = new String[] { "Option Key", "Option Value" };
+ private Button addTopButton;
+ private Button addBottomButton;
+ private TableViewerColumn keyColumn;
+ private OptionKeyEditingSupport keyEditingSupport;
+
+ public VolumeOptionsPage(final Composite parent, int style, Volume volume) {
+ super(parent, style);
+
+ this.volume = volume;
+
+ toolkit.adapt(this);
+ toolkit.paintBordersFor(this);
+
+ setupPageLayout();
+ addTopButton = createAddButton();
+ filterText = guiHelper.createFilterText(toolkit, this);
+
+ setupOptionsTableViewer(filterText);
+
+ addBottomButton = createAddButton();
+
+ if (defaultVolumeOptions.size() == volume.getOptions().size()) {
+ setAddButtonsEnabled(false);
+ }
+
+ tableViewer.setInput(volume.getOptions());
+
+ parent.layout(); // Important - this actually paints the table
+ registerListeners(parent);
+ }
+
+ private void setAddButtonsEnabled(boolean enable) {
+ addTopButton.setEnabled(enable);
+ addBottomButton.setEnabled(enable);
+ }
+
+ private Button createAddButton() {
+ return toolkit.createButton(this, "&Add", SWT.FLAT);
+ }
+
+ private void registerListeners(final Composite parent) {
+ /**
+ * Ideally not required. However the table viewer is not getting laid out properly on performing
+ * "maximize + restore" So this is a hack to make sure that the table is laid out again on re-size of the window
+ */
+ addPaintListener(new PaintListener() {
+
+ @Override
+ public void paintControl(PaintEvent e) {
+ parent.layout();
+ }
+ });
+
+ clusterListener = new DefaultClusterListener() {
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ super.volumeChanged(volume, event);
+
+ switch (event.getEventType()) {
+ case VOLUME_OPTIONS_RESET:
+ if (!tableViewer.getControl().isDisposed()) {
+ //While reseting the options, clear the filter text before refreshing the tree
+ filterText.setText("");
+ tableViewer.refresh();
+ setAddButtonsEnabled(true);
+ }
+ break;
+
+ case VOLUME_OPTION_SET:
+ String key = (String)event.getEventData();
+ if (isNewOption(volume, key)) {
+ // option has been set successfully by the user. re-enable the add button and search filter
+ // textbox
+ setAddButtonsEnabled(true);
+ filterText.setEnabled(true);
+ }
+
+ if (defaultVolumeOptions.size() == volume.getOptions().size()) {
+ setAddButtonsEnabled(false);
+ }
+
+ tableViewer.refresh();
+ break;
+ case VOLUME_CHANGED:
+ tableViewer.refresh();
+ if(volume.getOptions().size() == defaultVolumeOptions.size()) {
+ setAddButtonsEnabled(false);
+ } else {
+ setAddButtonsEnabled(true);
+ }
+ default:
+ break;
+ }
+ }
+
+ private boolean isNewOption(Volume volume, String optionKey) {
+ if (filterText.getText().length() > 0) {
+ // user has been filtering the contents. adding new option is allowed only when contents are NOT
+ // filtered. Thus it's impossible that this is a newly added option
+ return false;
+ }
+
+ // if this is the last option in the volume options, it must be the new option
+ return optionKey.equals(volume.getOptions().getOptions().get(volume.getOptions().size() - 1).getKey());
+ }
+ };
+
+ SelectionListener addButtonSelectionListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ // add an empty option to be filled up by user
+ volume.setOption("", "");
+
+ tableViewer.refresh();
+ tableViewer.setSelection(new StructuredSelection(getEntry("")));
+ keyColumn.getViewer().editElement(getEntry(""), 0); // edit newly created entry
+
+ // disable the add button AND search filter textbox till user fills up the new option
+ setAddButtonsEnabled(false);
+ filterText.setEnabled(false);
+ }
+
+ private VolumeOption getEntry(String key) {
+ for (VolumeOption entry : volume.getOptions().getOptions()) {
+ if (entry.getKey().equals(key)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+ };
+ addTopButton.addSelectionListener(addButtonSelectionListener);
+ addBottomButton.addSelectionListener(addButtonSelectionListener);
+
+ // Make sure that add button is enabled only when search filter textbox is empty
+ filterText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (filterText.getText().length() > 0) {
+ setAddButtonsEnabled(false);
+ } else {
+ if (defaultVolumeOptions.size() == volume.getOptions().size()) {
+ setAddButtonsEnabled(false);
+ } else {
+ setAddButtonsEnabled(true);
+ }
+ }
+ }
+ });
+
+ GlusterDataModelManager.getInstance().addClusterListener(clusterListener);
+
+ addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ toolkit.dispose();
+
+ if (!(addTopButton.isEnabled() || addBottomButton.isEnabled())) {
+ // user has selected key, but not added value. Since this is not a valid entry,
+ // remove the last option (without value) from the volume
+ volume.getOptions().remove(keyEditingSupport.getEntryBeingAdded().getKey());
+ }
+
+ GlusterDataModelManager.getInstance().removeClusterListener(clusterListener);
+ }
+ });
+ }
+
+ private void setupPageLayout() {
+ final GridLayout layout = new GridLayout(2, false);
+ layout.verticalSpacing = 10;
+ layout.marginTop = 10;
+ setLayout(layout);
+ }
+
+ private void setupOptionsTable(Composite parent) {
+ Table table = tableViewer.getTable();
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+
+ TableColumnLayout tableColumnLayout = createTableColumnLayout();
+ parent.setLayout(tableColumnLayout);
+
+ setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY, SWT.CENTER, 100);
+ setColumnProperties(table, OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE, SWT.CENTER, 100);
+ }
+
+ private TableColumnLayout createTableColumnLayout() {
+ TableColumnLayout tableColumnLayout = new TableColumnLayout();
+ ColumnLayoutData defaultColumnLayoutData = new ColumnWeightData(100);
+
+ tableColumnLayout.setColumnData(createKeyColumn(), defaultColumnLayoutData);
+ tableColumnLayout.setColumnData(createValueColumn(), defaultColumnLayoutData);
+
+ return tableColumnLayout;
+ }
+
+ private TableColumn createValueColumn() {
+ TableViewerColumn valueColumn = new TableViewerColumn(tableViewer, SWT.NONE);
+ valueColumn.getColumn()
+ .setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_VALUE.ordinal()]);
+ valueColumn.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ return ((VolumeOption) element).getValue();
+ }
+ });
+
+ // User can edit value of a volume option
+ valueColumn.setEditingSupport(new OptionValueEditingSupport(valueColumn.getViewer(), volume));
+
+ return valueColumn.getColumn();
+ }
+
+ private TableColumn createKeyColumn() {
+ keyColumn = new TableViewerColumn(tableViewer, SWT.NONE);
+ keyColumn.getColumn().setText(OPTIONS_TABLE_COLUMN_NAMES[OPTIONS_TABLE_COLUMN_INDICES.OPTION_KEY.ordinal()]);
+ keyColumn.setLabelProvider(new ColumnLabelProvider() {
+ @Override
+ public String getText(Object element) {
+ return ((VolumeOption) element).getKey();
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ String key = ((VolumeOption) element).getKey();
+ if (key.isEmpty()) {
+ return "Click to select a volume option key";
+ }
+
+ VolumeOptionInfo optionInfo = GlusterDataModelManager.getInstance().getVolumeOptionInfo(key);
+ // Wrap the description before adding to tooltip so that long descriptions are displayed properly
+ return WordUtils.wrap(optionInfo.getDescription(), 60) + CoreConstants.NEWLINE + "Default value: "
+ + optionInfo.getDefaultValue();
+ }
+ });
+
+ // Editing support required when adding new key
+ keyEditingSupport = new OptionKeyEditingSupport(keyColumn.getViewer(), volume);
+ keyColumn.setEditingSupport(keyEditingSupport);
+
+ return keyColumn.getColumn();
+ }
+
+ private void createOptionsTableViewer(Composite parent) {
+ tableViewer = new TableViewer(parent, SWT.FLAT | SWT.FULL_SELECTION | SWT.SINGLE);
+ tableViewer.setLabelProvider(new VolumeOptionsTableLabelProvider());
+ tableViewer.setContentProvider(new VolumeOptionsContentProvider());
+ tableViewer.getTable().setLinesVisible(true);
+
+ setupOptionsTable(parent);
+ }
+
+ private Composite createTableViewerComposite() {
+ Composite tableViewerComposite = new Composite(this, SWT.NO);
+ tableViewerComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
+
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.horizontalSpan = 2;
+ tableViewerComposite.setLayoutData(layoutData);
+
+ return tableViewerComposite;
+ }
+
+ private void setupOptionsTableViewer(final Text filterText) {
+ Composite tableViewerComposite = createTableViewerComposite();
+ createOptionsTableViewer(tableViewerComposite);
+ ColumnViewerToolTipSupport.enableFor(tableViewer);
+ // Create a case insensitive filter for the table viewer using the filter text field
+ guiHelper.createFilter(tableViewer, filterText, false);
+ }
+
+ private void setColumnProperties(Table table, OPTIONS_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumesPage.java b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumesPage.java
new file mode 100644
index 00000000..60d00a7f
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/org/gluster/storage/management/console/views/pages/VolumesPage.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.console.views.pages;
+
+import java.util.List;
+
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.IWorkbenchSite;
+import org.gluster.storage.management.console.EntityGroupContentProvider;
+import org.gluster.storage.management.console.VolumeTableLabelProvider;
+import org.gluster.storage.management.console.toolbar.GlusterToolbarManager;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.model.ClusterListener;
+import org.gluster.storage.management.core.model.DefaultClusterListener;
+import org.gluster.storage.management.core.model.EntityGroup;
+import org.gluster.storage.management.core.model.Event;
+import org.gluster.storage.management.core.model.Volume;
+
+
+public class VolumesPage extends AbstractTableViewerPage<Volume> {
+ private List<Volume> volumes;
+
+ final GlusterToolbarManager toolbarManager = new GlusterToolbarManager( site.getWorkbenchWindow());
+
+ public enum VOLUME_TABLE_COLUMN_INDICES {
+ NAME, VOLUME_TYPE, NUM_OF_BRICKS, TRANSPORT_TYPE, VOLUME_STATUS
+ };
+
+ private static final String[] VOLUME_TABLE_COLUMN_NAMES = new String[] { "Name", "Volume Type",
+ "Number of" + CoreConstants.NEWLINE + "Bricks", "Transport Type", "Status" };
+
+ public VolumesPage(final Composite parent, IWorkbenchSite site, EntityGroup<Volume> volumes) {
+ super(site, parent, SWT.NONE, true, true, volumes);
+ this.volumes = volumes.getEntities();
+ }
+
+ @Override
+ protected String[] getColumnNames() {
+ return VOLUME_TABLE_COLUMN_NAMES;
+ }
+
+ @Override
+ protected void setColumnProperties(Table table) {
+ setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.VOLUME_STATUS, SWT.CENTER, 50);
+ setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.NUM_OF_BRICKS, SWT.CENTER, 50);
+ setColumnProperties(table, VOLUME_TABLE_COLUMN_INDICES.TRANSPORT_TYPE, SWT.CENTER, 70);
+ }
+
+ @Override
+ protected IBaseLabelProvider getLabelProvider() {
+ return new VolumeTableLabelProvider();
+ }
+
+ @Override
+ protected IContentProvider getContentProvider() {
+ return new EntityGroupContentProvider<Volume>();
+ }
+
+ @Override
+ protected ClusterListener createClusterListener() {
+ return new DefaultClusterListener() {
+ @Override
+ public void volumeCreated(Volume volume) {
+ tableViewer.add(volume);
+ parent.update();
+ toolbarManager.updateToolbar(volume);
+ }
+
+ @Override
+ public void volumeDeleted(Volume volume) {
+ tableViewer.remove(volume);
+ parent.update();
+ toolbarManager.updateToolbar(volume);
+ }
+
+ @Override
+ public void volumeChanged(Volume volume, Event event) {
+ tableViewer.update(volume, null);
+ parent.update();
+ toolbarManager.updateToolbar(volume);
+ }
+ };
+ }
+
+ /**
+ * Sets properties for alignment and weight of given column of given table
+ *
+ * @param table
+ * @param columnIndex
+ * @param alignment
+ * @param weight
+ */
+ public void setColumnProperties(Table table, VOLUME_TABLE_COLUMN_INDICES columnIndex, int alignment, int weight) {
+ TableColumn column = table.getColumn(columnIndex.ordinal());
+ column.setAlignment(alignment);
+
+ TableColumnLayout tableColumnLayout = (TableColumnLayout) table.getParent().getLayout();
+ tableColumnLayout.setColumnData(column, new ColumnWeightData(weight));
+ }
+
+ @Override
+ protected List<Volume> getAllEntities() {
+ return volumes;
+ }
+
+ @Override
+ protected ViewerComparator createViewerComparator() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/org.gluster.storage.management.console/src/test.xml b/src/org.gluster.storage.management.console/src/test.xml
new file mode 100644
index 00000000..12bbf745
--- /dev/null
+++ b/src/org.gluster.storage.management.console/src/test.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?>