/*******************************************************************************
* 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.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);
}
}