/*******************************************************************************
* Copyright (c) 2006-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 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 General Public License for more details.
*
* You should have received a copy of the GNU 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);
}
}
}
}
});
}
}