/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.gui.cluster.view.internal; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.jface.action.Action; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.SelectionAdapter; 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.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.part.ViewPart; import de.rcenvironment.core.gui.cluster.configuration.internal.ClusterConnectionConfigurationDialogsController; import de.rcenvironment.core.gui.cluster.internal.ErrorMessageDialogFactory; import de.rcenvironment.core.utils.cluster.ClusterService; import de.rcenvironment.core.utils.common.StringUtils; /** * View monitoring information about cluster jobs. * * @author Doreen Seider */ public class ClusterJobMonitorView extends ViewPart { private static final String CONNECTING_TO_CLUSTER_FAILED = "Connecting to cluster failed"; private static final String FETCHING_CLUSTER_JOB_INFORMATION_FAILED = "Fetching cluster job information failed"; private static final int COLUMN_WIDTH = 120; private static final int COLUMN_WIDTH_JOBSTATE = 100; private static final int NO_SPACE = 0; private static final int PLATFORM_WIDTH = 250; private static final int TEXT_WIDTH = PLATFORM_WIDTH; private static final int DELAY = 30000; private static final Log LOGGER = LogFactory.getLog(ClusterJobMonitorView.class); private Button othersCheckbox; private Button runningCheckbox; private Button queuedCheckbox; private Combo connectedConfigurationNameCombo; private ClusterJobInformationTableFilter tableRowFilter; private ClusterJobInformationTableColumnSorter tableColumnSorter; private TableViewer jobInformationTableViewer; private Text searchText; private Composite parent; private Timer getUpdateTimer; private volatile boolean getUpdateTimerTaskScheduled = false; private final Action connectAction = new Action(Messages.connectToolTip, ImageDescriptor.createFromURL( ClusterJobMonitorView.class.getResource("/resources/icons/connect16.png"))) { @Override public void run() { final ClusterConnectionConfigurationDialogsController controller = new ClusterConnectionConfigurationDialogsController(parent); final ClusterConnectionInformation connectionInformation = controller.openClusterConnectionSelectionDialog(); if (connectionInformation != null) { BusyIndicator.showWhile(jobInformationTableViewer.getTable().getDisplay(), new Runnable() { @Override public void run() { String clusterConfigurationName = controller.getClusterConfigurationName(); ClusterService clusterInformationService = controller.getClusterJobInformationService(); if (updateModelForFirstTime(clusterConfigurationName, clusterInformationService, connectionInformation)) { refreshView(clusterConfigurationName); scheduleGetUpdateOfClusterJobInformationTimerIfNeeded(); } } }); } } }; private final Action disconnectAction = new Action(Messages.disconnectToolTip, ImageDescriptor.createFromURL( ClusterJobMonitorView.class.getResource("/resources/icons/disconnect16.png"))) { @Override public void run() { String clusterConfigurationName = connectedConfigurationNameCombo.getItem(connectedConfigurationNameCombo.getSelectionIndex()); ClusterJobInformationModel model = ClusterJobInformationModel.getInstance(); model.removeConnectedCluster(clusterConfigurationName); refreshConnectedClusterComboAndToolBar(null); clusterConfigurationName = connectedConfigurationNameCombo.getItem(connectedConfigurationNameCombo.getSelectionIndex()); model.setSelectedConnectedConfigurationName(clusterConfigurationName); refreshClusterJobInformationTableViewer(); cancelUpdateClusterJobInformationTimerIfNeeded(); } }; private final Action refreshAction = new Action(Messages.refreshToolTip, ImageDescriptor.createFromURL( ClusterJobMonitorView.class.getResource("/resources/icons/refresh.gif"))) { @Override public void run() { BusyIndicator.showWhile(jobInformationTableViewer.getTable().getDisplay(), new Runnable() { @Override public void run() { getUpdateOfClusterJobInformation(); refreshClusterJobInformationTableViewer(); } }); } }; private final Action informationAction = new Action(Messages.informationToolTip, ImageDescriptor.createFromURL( ClusterJobMonitorView.class.getResource("/resources/icons/information.gif"))) { @Override public void run() { ClusterJobInformationModel model = ClusterJobInformationModel.getInstance(); String connectedConfigurationName = connectedConfigurationNameCombo .getItem(connectedConfigurationNameCombo.getSelectionIndex()); ClusterConnectionInformation connectionInformation = model.getClusterConnectionInformation(connectedConfigurationName); MessageDialog dialog = new MessageDialog(parent.getShell(), Messages.informationDialogTitle, null, StringUtils.format(Messages.informationDialogMessage, connectionInformation.getHost(), connectionInformation.getUsername(), connectionInformation.getConnectedDate(), connectionInformation.getLastUpdateDate(), connectionInformation.getUpdateInterval()), MessageDialog.INFORMATION, new String[] { Messages.ok }, 0); dialog.open(); } }; @Override public void createPartControl(Composite aParent) { this.parent = aParent; aParent.setLayout(new GridLayout(1, false)); // filter = cluster selection, state selection, and search text field Composite filterComposite = new Composite(aParent, SWT.NONE); filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); filterComposite.setLayout(new RowLayout()); createConnectedClusterListingArrangement(filterComposite); createLevelArrangement(filterComposite); createSearchArrangement(filterComposite); createTableArrangement(aParent); tableColumnSorter = new ClusterJobInformationTableColumnSorter(); jobInformationTableViewer.setSorter(tableColumnSorter); tableRowFilter = new ClusterJobInformationTableFilter(this, jobInformationTableViewer); searchText.addKeyListener(tableRowFilter); queuedCheckbox.addSelectionListener(tableRowFilter); runningCheckbox.addSelectionListener(tableRowFilter); othersCheckbox.addSelectionListener(tableRowFilter); connectedConfigurationNameCombo.addSelectionListener(tableRowFilter); jobInformationTableViewer.addFilter(tableRowFilter); for (Action action : createToolbarActions()) { getViewSite().getActionBars().getToolBarManager().add(action); } String[] connectedConfigurationNames = ClusterJobInformationModel.getInstance().getConnectedConfigurationNames(); boolean enabled = connectedConfigurationNames.length > 0 && !connectedConfigurationNames[0].equals(ClusterJobInformationModel.NOT_CONNECTED); disconnectAction.setEnabled(enabled); refreshAction.setEnabled(enabled); informationAction.setEnabled(enabled); } @Override public void setFocus() { jobInformationTableViewer.getControl().setFocus(); scheduleGetUpdateOfClusterJobInformationTimerIfNeeded(); } @Override public void dispose() { cancelUpdateClusterJobInformationTimerIfNeeded(); } public boolean getQueuedSelection() { return queuedCheckbox.getSelection(); } public boolean getRunningSelection() { return runningCheckbox.getSelection(); } public boolean getOthersSelection() { return othersCheckbox.getSelection(); } public String getSelectedConnectedConfigurationName() { return connectedConfigurationNameCombo.getItem(connectedConfigurationNameCombo.getSelectionIndex()); } public String getSearchText() { return searchText.getText(); } private Action[] createToolbarActions() { return new Action[] { connectAction, disconnectAction, refreshAction, informationAction }; } private void createLevelArrangement(Composite filterComposite) { RowLayout rowLayout = new RowLayout(); rowLayout.spacing = NO_SPACE; filterComposite.setLayout(rowLayout); queuedCheckbox = new Button(filterComposite, SWT.CHECK); queuedCheckbox.setText(Messages.queuedFilter); queuedCheckbox.setSelection(true); runningCheckbox = new Button(filterComposite, SWT.CHECK); runningCheckbox.setText(Messages.runningFilter); runningCheckbox.setSelection(true); othersCheckbox = new Button(filterComposite, SWT.CHECK); othersCheckbox.setText(Messages.othersFilter); othersCheckbox.setSelection(true); } private void createConnectedClusterListingArrangement(Composite connectedClusterComposite) { RowLayout rowLayout = new RowLayout(); rowLayout.spacing = NO_SPACE; connectedClusterComposite.setLayout(rowLayout); connectedConfigurationNameCombo = new Combo(connectedClusterComposite, SWT.DROP_DOWN | SWT.READ_ONLY); connectedConfigurationNameCombo.setLayoutData(new RowData(PLATFORM_WIDTH, SWT.DEFAULT)); connectedConfigurationNameCombo.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent event) { ClusterJobInformationModel.getInstance().setSelectedConnectedConfigurationName( connectedConfigurationNameCombo.getItem(connectedConfigurationNameCombo.getSelectionIndex())); refreshClusterJobInformationTableViewer(); } @Override public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); } }); refreshConnectedClusterComboAndToolBar(null); } private void createSearchArrangement(Composite searchComposite) { RowLayout rowLayout = new RowLayout(); rowLayout.spacing = 7; searchComposite.setLayout(rowLayout); searchText = new Text(searchComposite, SWT.SEARCH); searchText.setMessage(Messages.searchFilter); searchText.setSize(TEXT_WIDTH, SWT.DEFAULT); searchText.setLayoutData(new RowData(TEXT_WIDTH, SWT.DEFAULT)); } private void createTableArrangement(Composite tableComposite) { tableComposite.setLayout(new GridLayout()); jobInformationTableViewer = new TableViewer(tableComposite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI); jobInformationTableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); // create table header and column styles String[] columnTitles = new String[] { Messages.columnJobId, Messages.columnJobName, Messages.columnUser, Messages.columnQueue, Messages.columnRemainingTime, Messages.columnStartTime, Messages.columnQueueTime, Messages.columnJobState }; int[] bounds = { COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH_JOBSTATE }; for (int i = 0; i < columnTitles.length; i++) { // for all columns final int index = i; final TableViewerColumn viewerColumn = new TableViewerColumn(jobInformationTableViewer, SWT.NONE); final TableColumn column = viewerColumn.getColumn(); // set column properties column.setText(columnTitles[i]); column.setWidth(bounds[i]); column.setResizable(true); column.setMoveable(true); column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { tableColumnSorter.setColumn(index); int direction = jobInformationTableViewer.getTable().getSortDirection(); if (jobInformationTableViewer.getTable().getSortColumn() == column) { if (direction == SWT.UP) { direction = SWT.DOWN; } else { direction = SWT.UP; } } else { direction = SWT.UP; } jobInformationTableViewer.getTable().setSortDirection(direction); jobInformationTableViewer.getTable().setSortColumn(column); refreshClusterJobInformationTableViewer(); } }); } jobInformationTableViewer.setContentProvider(new ClusterJobInformationContentProvider()); jobInformationTableViewer.setLabelProvider(new ClusterJobInformationLabelProvider()); jobInformationTableViewer.setInput(ClusterJobInformationModel.getInstance()); // set table layout data final Table table = jobInformationTableViewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(true); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Menu contextMenu = new Menu(tableComposite); final MenuItem killJobItem = new MenuItem(contextMenu, SWT.PUSH); killJobItem.setText(Messages.cancelJob); killJobItem.setEnabled(table.getSelectionCount() > 0); killJobItem.addSelectionListener(new KillClusterJobListenerListener(jobInformationTableViewer, refreshAction)); jobInformationTableViewer.getControl().setMenu(contextMenu); table.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent event) { killJobItem.setEnabled(table.getSelectionCount() > 0); } @Override public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); } }); } private synchronized void getUpdateOfClusterJobInformation() { try { ClusterJobInformationModel.getInstance().getUpdateFromCluster(); } catch (final IOException e) { jobInformationTableViewer.getTable().getDisplay().asyncExec(new Runnable() { @Override public void run() { LOGGER.error(FETCHING_CLUSTER_JOB_INFORMATION_FAILED, e); disconnectAction.run(); ErrorMessageDialogFactory.createMessageDialogForFetchingFailure(parent).open(); } }); } } private boolean updateModelForFirstTime(String connectedClusterConfigurationName, ClusterService clusterInformationService, ClusterConnectionInformation connectionInformation) { ClusterJobInformationModel model = ClusterJobInformationModel.getInstance(); model.addConnectedCluster(connectedClusterConfigurationName, clusterInformationService); final int convertToSecondsQuotient = 1000; connectionInformation.setUpdateInterval(ClusterService.FETCH_INTERVAL / convertToSecondsQuotient); model.addClusterConnectionInformation(connectedClusterConfigurationName, connectionInformation); model.setSelectedConnectedConfigurationName(connectedClusterConfigurationName); try { model.getUpdateFromCluster(); } catch (IOException e) { ErrorMessageDialogFactory.createMessageDialogForConnectionFailure(parent, e).open(); LOGGER.error(CONNECTING_TO_CLUSTER_FAILED, e); model.removeConnectedCluster(connectedClusterConfigurationName); return false; } return true; } private void refreshView(String connectedClusterConfigurationName) { refreshConnectedClusterComboAndToolBar(connectedClusterConfigurationName); refreshClusterJobInformationTableViewer(); } private void refreshConnectedClusterComboAndToolBar(String connectedClusterConfigurationName) { connectedConfigurationNameCombo.setItems(ClusterJobInformationModel.getInstance().getConnectedConfigurationNames()); if (connectedClusterConfigurationName != null && !connectedClusterConfigurationName.isEmpty()) { connectedConfigurationNameCombo.select(connectedConfigurationNameCombo.indexOf(connectedClusterConfigurationName)); disconnectAction.setEnabled(true); refreshAction.setEnabled(true); informationAction.setEnabled(true); } else { connectedConfigurationNameCombo.select(0); if (!isConnectedToAtLeastOneCluster()) { disconnectAction.setEnabled(false); refreshAction.setEnabled(false); informationAction.setEnabled(false); } } } private void refreshClusterJobInformationTableViewer() { jobInformationTableViewer.getTable().clearAll(); jobInformationTableViewer.refresh(); } private void scheduleGetUpdateOfClusterJobInformationTimerIfNeeded() { if (!getUpdateTimerTaskScheduled && isConnectedToAtLeastOneCluster()) { TimerTask getUpdateTimerTask = new TimerTask() { @Override public void run() { Job job = new Job(Messages.updateJobTitle) { @Override protected IStatus run(IProgressMonitor monitor) { try { monitor.beginTask(Messages.updateJobMessage, 3); monitor.worked(1); getUpdateOfClusterJobInformation(); monitor.worked(2); if (!jobInformationTableViewer.getTable().isDisposed()) { jobInformationTableViewer.getTable().getDisplay().asyncExec(new Runnable() { @Override public void run() { refreshClusterJobInformationTableViewer(); } }); } } finally { monitor.done(); } return Status.OK_STATUS; }; }; job.setUser(false); job.schedule(); } }; getUpdateTimer = new Timer("Get Update (Cluster Job Information) Timer", true); getUpdateTimer.schedule(getUpdateTimerTask, DELAY, ClusterService.FETCH_INTERVAL); getUpdateTimerTaskScheduled = true; } } private void cancelUpdateClusterJobInformationTimerIfNeeded() { if (getUpdateTimerTaskScheduled && !isConnectedToAtLeastOneCluster()) { getUpdateTimer.cancel(); getUpdateTimerTaskScheduled = false; } } private boolean isConnectedToAtLeastOneCluster() { return !connectedConfigurationNameCombo.getItem(connectedConfigurationNameCombo.getSelectionIndex()) .equals(ClusterJobInformationModel.NOT_CONNECTED); } }