Java tutorial
/* * Copyright (c) 2012 Diamond Light Source Ltd. * * 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 */ package org.eclipse.scanning.event.ui.view; import java.io.File; import java.net.URI; import java.text.DateFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.EventListener; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.IContentProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.scanning.api.event.EventConstants; import org.eclipse.scanning.api.event.EventException; import org.eclipse.scanning.api.event.IEventService; import org.eclipse.scanning.api.event.alive.PauseBean; import org.eclipse.scanning.api.event.bean.BeanEvent; import org.eclipse.scanning.api.event.bean.IBeanListener; import org.eclipse.scanning.api.event.core.ConsumerConfiguration; import org.eclipse.scanning.api.event.core.IPublisher; import org.eclipse.scanning.api.event.core.IQueueReader; import org.eclipse.scanning.api.event.core.ISubmitter; import org.eclipse.scanning.api.event.core.ISubscriber; import org.eclipse.scanning.api.event.status.AdministratorMessage; import org.eclipse.scanning.api.event.status.StatusBean; import org.eclipse.scanning.api.ui.IModifyHandler; import org.eclipse.scanning.api.ui.IRerunHandler; import org.eclipse.scanning.api.ui.IResultHandler; import org.eclipse.scanning.event.ui.Activator; import org.eclipse.scanning.event.ui.ServiceHolder; import org.eclipse.scanning.event.ui.dialog.PropertiesDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; 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.TableItem; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.osgi.framework.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A view for which the secondary id MUST be set and provides the queueName * and optionally the queue view name if a custom one is required. Syntax of * these parameters in the secondary id are key1=value1;key2=value2... * * The essential keys are: beanBundleName, beanClassName, queueName, topicName, submissionQueueName * You can use createId(...) to generate a legal id from them. * * The optional keys are: partName, * uri (default CommandConstants.JMS_URI), * userName (default is user.name system property) * * Example id for this view would be: * org.eclipse.scanning.event.ui.queueView:beanClassName=org.dawnsci.commandserver.mx.beans.ProjectBean;beanBundleName=org.dawnsci.commandserver.mx * * You can optionally extend this class to provide a table which is displayed for your * queue of custom objects. For instance for a queue showing xia2 reruns, the * extra columns for this could be defined. However by default the * * @author Matthew Gerring * */ public class StatusQueueView extends EventConnectionView { public static final String ID = "org.eclipse.scanning.event.ui.queueView"; private static final Logger logger = LoggerFactory.getLogger(StatusQueueView.class); // UI private TableViewer viewer; // Data private Map<String, StatusBean> queue; private boolean showEntireQueue = false; private ISubscriber<IBeanListener<StatusBean>> topicMonitor; private ISubscriber<IBeanListener<PauseBean>> pauseMonitor; private ISubscriber<IBeanListener<AdministratorMessage>> adminMonitor; private ISubmitter<StatusBean> queueConnection; private Action rerun, edit, remove, up, down, pause, pauseConsumer; private IEventService service; private ISubscriber<EventListener> pauseSubscriber; public StatusQueueView() { this.service = ServiceHolder.getEventService(); } @Override public void createPartControl(Composite content) { content.setLayout(new GridLayout(1, false)); Util.removeMargins(content); this.viewer = new TableViewer(content, SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL); viewer.setUseHashlookup(true); viewer.getTable().setHeaderVisible(true); viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createColumns(); viewer.setContentProvider(createContentProvider()); try { queueConnection = service.createSubmitter(getUri(), getSubmissionQueueName()); queueConnection.setStatusTopicName(getTopicName()); updateQueue(getUri()); String name = getSecondaryIdAttribute("partName"); if (name != null) setPartName(name); createActions(); // We just use this submitter to read the queue createTopicListener(getUri()); } catch (Exception e) { logger.error("Cannot listen to topic of command server!", e); } getViewSite().setSelectionProvider(viewer); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { updateSelected(); } }); } protected void updateSelected() { StatusBean bean = getSelection(); if (bean == null) bean = new StatusBean(); remove.setEnabled(bean.getStatus() != null); rerun.setEnabled(true); boolean isSubmitted = bean.getStatus() == org.eclipse.scanning.api.event.status.Status.SUBMITTED; up.setEnabled(isSubmitted); edit.setEnabled(isSubmitted); down.setEnabled(isSubmitted); pause.setEnabled(bean.getStatus().isRunning() || bean.getStatus().isPaused()); pause.setChecked(bean.getStatus().isPaused()); pause.setText(bean.getStatus().isPaused() ? "Resume job" : "Pause job"); } /** * Listens to a topic */ private void createTopicListener(final URI uri) throws Exception { // Use job because connection might timeout. final Job topicJob = new Job("Create topic listener") { @Override protected IStatus run(IProgressMonitor monitor) { try { topicMonitor = service.createSubscriber(uri, getTopicName()); topicMonitor.addListener(new IBeanListener<StatusBean>() { @Override public void beanChangePerformed(BeanEvent<StatusBean> evt) { final StatusBean bean = evt.getBean(); try { mergeBean(bean); } catch (Exception e) { logger.error("Cannot merge changed bean!"); } } }); adminMonitor = service.createSubscriber(uri, IEventService.ADMIN_MESSAGE_TOPIC); adminMonitor.addListener(new IBeanListener<AdministratorMessage>() { @Override public void beanChangePerformed(BeanEvent<AdministratorMessage> evt) { final AdministratorMessage bean = evt.getBean(); getSite().getShell().getDisplay().syncExec(new Runnable() { public void run() { MessageDialog.openError(getViewSite().getShell(), bean.getTitle(), bean.getMessage()); viewer.refresh(); } }); } }); return Status.OK_STATUS; } catch (Exception ne) { logger.error("Cannot listen to topic changes because command server is not there", ne); return Status.CANCEL_STATUS; } } }; topicJob.setPriority(Job.INTERACTIVE); topicJob.setSystem(true); topicJob.setUser(false); topicJob.schedule(); } public void dispose() { super.dispose(); try { if (topicMonitor != null) topicMonitor.disconnect(); if (adminMonitor != null) adminMonitor.disconnect(); if (pauseSubscriber != null) pauseSubscriber.disconnect(); } catch (Exception ne) { logger.warn("Problem stopping topic listening for " + getTopicName(), ne); } } /** * Updates the bean if it is found in the list, otherwise * refreshes the whole list because a bean we are not reporting * has been(bean?) encountered. * * @param bean */ protected void mergeBean(final StatusBean bean) throws Exception { getSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { if (queue.containsKey(bean.getUniqueId())) { queue.get(bean.getUniqueId()).merge(bean); viewer.refresh(); updateSelected(); } else { reconnect(); } } }); } private void createActions() throws Exception { final IContributionManager toolMan = getViewSite().getActionBars().getToolBarManager(); final IContributionManager dropDown = getViewSite().getActionBars().getMenuManager(); final MenuManager menuMan = new MenuManager(); final Action openResults = new Action("Open results for selected run", Activator.getImageDescriptor("icons/results.png")) { public void run() { openResults(getSelection()); } }; toolMan.add(openResults); toolMan.add(new Separator()); menuMan.add(openResults); menuMan.add(new Separator()); dropDown.add(openResults); dropDown.add(new Separator()); this.up = new Action("Less urgent (-1)", Activator.getImageDescriptor("icons/arrow-090.png")) { public void run() { final StatusBean bean = getSelection(); try { queueConnection.reorder(bean, -1); } catch (EventException e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot move " + bean.getName(), "'" + bean.getName() + "' cannot be moved in the submission queue.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } refresh(); } }; up.setEnabled(false); toolMan.add(up); menuMan.add(up); dropDown.add(up); this.down = new Action("More urgent (+1)", Activator.getImageDescriptor("icons/arrow-270.png")) { public void run() { final StatusBean bean = getSelection(); try { queueConnection.reorder(getSelection(), +1); } catch (EventException e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot move " + bean.getName(), e.getMessage(), new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } refresh(); } }; down.setEnabled(false); toolMan.add(down); menuMan.add(down); dropDown.add(down); this.pause = new Action("Pause job.\nPauses a running job.", IAction.AS_CHECK_BOX) { public void run() { pauseJob(); } }; pause.setImageDescriptor(Activator.getImageDescriptor("icons/control-pause.png")); pause.setEnabled(false); pause.setChecked(false); toolMan.add(pause); menuMan.add(pause); dropDown.add(pause); this.pauseConsumer = new Action("Pause " + getPartName() + " Queue.\nDoes not pause running job.", IAction.AS_CHECK_BOX) { public void run() { togglePausedConsumer(this); } }; pauseConsumer.setImageDescriptor(Activator.getImageDescriptor("icons/control-pause-red.png")); pauseConsumer.setChecked(isQueuePaused(getSubmissionQueueName())); toolMan.add(pauseConsumer); menuMan.add(pauseConsumer); dropDown.add(pauseConsumer); this.pauseMonitor = service.createSubscriber(getUri(), EventConstants.CMD_TOPIC); pauseMonitor.addListener(new IBeanListener<PauseBean>() { @Override public void beanChangePerformed(BeanEvent<PauseBean> evt) { pauseConsumer.setChecked(isQueuePaused(getSubmissionQueueName())); } }); this.remove = new Action("Stop job or remove if finished", Activator.getImageDescriptor("icons/control-stop-square.png")) { public void run() { stopJob(); } }; remove.setEnabled(false); toolMan.add(remove); menuMan.add(remove); dropDown.add(remove); this.rerun = new Action("Rerun...", Activator.getImageDescriptor("icons/rerun.png")) { public void run() { rerunSelection(); } }; rerun.setEnabled(false); toolMan.add(rerun); menuMan.add(rerun); dropDown.add(rerun); this.edit = new Action("Edit...", Activator.getImageDescriptor("icons/modify.png")) { public void run() { editSelection(); } }; edit.setEnabled(false); toolMan.add(edit); menuMan.add(edit); dropDown.add(edit); toolMan.add(new Separator()); menuMan.add(new Separator()); final Action showAll = new Action("Show other users results", IAction.AS_CHECK_BOX) { public void run() { showEntireQueue = isChecked(); viewer.refresh(); } }; showAll.setImageDescriptor(Activator.getImageDescriptor("icons/spectacle-lorgnette.png")); toolMan.add(showAll); menuMan.add(showAll); dropDown.add(showAll); toolMan.add(new Separator()); menuMan.add(new Separator()); dropDown.add(new Separator()); final Action refresh = new Action("Refresh", Activator.getImageDescriptor("icons/arrow-circle-double-135.png")) { public void run() { reconnect(); } }; toolMan.add(refresh); menuMan.add(refresh); dropDown.add(refresh); final Action configure = new Action("Configure...", Activator.getImageDescriptor("icons/document--pencil.png")) { public void run() { PropertiesDialog dialog = new PropertiesDialog(getSite().getShell(), idProperties); int ok = dialog.open(); if (ok == PropertiesDialog.OK) { idProperties.clear(); idProperties.putAll(dialog.getProps()); reconnect(); } } }; toolMan.add(configure); menuMan.add(configure); dropDown.add(configure); final Action clearQueue = new Action("Clear Queue") { public void run() { try { purgeQueues(); } catch (EventException e) { e.printStackTrace(); logger.error("Canot purge queues", e); } } }; menuMan.add(new Separator()); dropDown.add(new Separator()); menuMan.add(clearQueue); dropDown.add(clearQueue); viewer.getControl().setMenu(menuMan.createContextMenu(viewer.getControl())); } private boolean isQueuePaused(String submissionQueueName) { PauseBean bean = getPauseBean(submissionQueueName); return bean != null ? bean.isPause() : false; } private PauseBean getPauseBean(String submissionQueueName) { IQueueReader<PauseBean> qr = null; try { qr = service.createQueueReader(getUri(), EventConstants.CMD_SET); qr.setBeanClass(PauseBean.class); List<PauseBean> pausedList = qr.getQueue(); // The most recent bean in the queue is the latest for (PauseBean pauseBean : pausedList) { if (submissionQueueName.equals(pauseBean.getQueueName())) return pauseBean; } } catch (Exception ne) { logger.error("Cannot get queue " + EventConstants.CMD_SET, ne); return null; } finally { try { if (qr != null) qr.disconnect(); } catch (EventException e) { logger.error("Cannot get disconnect " + EventConstants.CMD_SET, e); } } return null; } protected void togglePausedConsumer(IAction pauseConsumer) { // The button can get out of sync if two clients are used. final boolean currentState = isQueuePaused(getSubmissionQueueName()); try { pauseConsumer.setChecked(!currentState); // We are toggling it. IPublisher<PauseBean> pauser = service.createPublisher(getUri(), IEventService.CMD_TOPIC); pauser.setStatusSetName(IEventService.CMD_SET); // The set that other clients may check pauser.setStatusSetAddRequired(true); PauseBean pbean = new PauseBean(); pbean.setQueueName(getSubmissionQueueName()); // The queue we are pausing pbean.setPause(pauseConsumer.isChecked()); pauser.broadcast(pbean); } catch (Exception e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot pause queue " + getSubmissionQueueName(), "Cannot pause queue " + getSubmissionQueueName() + "\n\nPlease contact your support representative.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } } protected void pauseJob() { final StatusBean bean = getSelection(); if (bean == null) return; if (bean.getStatus().isFinal()) { MessageDialog.openInformation(getViewSite().getShell(), "Run '" + bean.getName() + "' inactive", "Run '" + bean.getName() + "' is inactive and cannot be paused."); return; } try { if (bean.getStatus().isPaused()) { bean.setStatus(org.eclipse.scanning.api.event.status.Status.REQUEST_RESUME); bean.setMessage("Resume of " + bean.getName()); } else { bean.setStatus(org.eclipse.scanning.api.event.status.Status.REQUEST_PAUSE); bean.setMessage("Pause of " + bean.getName()); } IPublisher<StatusBean> terminate = service.createPublisher(getUri(), getTopicName()); terminate.broadcast(bean); } catch (Exception e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot pause " + bean.getName(), "Cannot pause " + bean.getName() + "\n\nPlease contact your support representative.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } } protected void stopJob() { final StatusBean bean = getSelection(); if (bean == null) return; if (!bean.getStatus().isActive()) { String queueName = null; if (bean.getStatus() != org.eclipse.scanning.api.event.status.Status.SUBMITTED) { queueName = getQueueName(); boolean ok = MessageDialog.openQuestion(getSite().getShell(), "Confirm Remove '" + bean.getName() + "'", "Are you sure you would like to remove '" + bean.getName() + "'?"); if (!ok) return; } else { // Submitted delete it right away without asking or the consumer will run it! queueName = getSubmissionQueueName(); } // It is submitted and not running. We can probably delete it. try { queueConnection.remove(bean, queueName); refresh(); } catch (EventException e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot delete " + bean.getName(), "Cannot delete " + bean.getName() + "\n\nIt might have changed state at the same time and being remoted.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } return; } try { final DateFormat format = DateFormat.getDateTimeInstance(); boolean ok = MessageDialog.openQuestion(getViewSite().getShell(), "Confirm terminate " + bean.getName(), "Are you sure you want to terminate " + bean.getName() + " submitted on " + format.format(new Date(bean.getSubmissionTime())) + "?"); if (!ok) return; bean.setStatus(org.eclipse.scanning.api.event.status.Status.REQUEST_TERMINATE); bean.setMessage("Termination of " + bean.getName()); IPublisher<StatusBean> terminate = service.createPublisher(getUri(), getTopicName()); terminate.broadcast(bean); } catch (Exception e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot terminate " + bean.getName(), "Cannot terminate " + bean.getName() + "\n\nPlease contact your support representative.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } } protected void purgeQueues() throws EventException { boolean ok = MessageDialog.openQuestion(getSite().getShell(), "Confirm Clear Queues", "Are you sure you would like to remove all items from the queue " + getQueueName() + " and " + getSubmissionQueueName() + "?\n\nThis could abort or disconnect runs of other users."); if (!ok) return; queueConnection.clearQueue(getQueueName()); queueConnection.clearQueue(getSubmissionQueueName()); reconnect(); } /** * You can override this method to provide custom opening of * results if required. * * @param bean */ protected void openResults(StatusBean bean) { if (bean == null) return; if (!bean.getStatus().isFinal()) { boolean ok = MessageDialog.openQuestion(getSite().getShell(), "'" + bean.getName() + "' incomplete.", "The run of '" + bean.getName() + "' has not completed.\n" + "Would you like to try to open the results anyway?"); if (!ok) return; } try { final IConfigurationElement[] c = Platform.getExtensionRegistry() .getConfigurationElementsFor("org.eclipse.scanning.api.resultsHandler"); if (c != null) { for (IConfigurationElement i : c) { final IResultHandler handler = (IResultHandler) i.createExecutableExtension("class"); handler.init(service, createConsumerConfiguration()); if (handler.isHandled(bean)) { boolean ok = handler.open(bean); if (ok) return; } } } } catch (Exception ne) { ErrorDialog.openError(getSite().getShell(), "Internal Error", "Cannot open " + bean.getRunDirectory() + " normally, will show directory instead.\n\nPlease contact your support representative.", new Status(IStatus.ERROR, Activator.PLUGIN_ID, ne.getMessage())); } openDirectory(bean); } private void openDirectory(StatusBean bean) { try { final IWorkbenchPage page = Util.getPage(); final File fdir = new File(Util.getSanitizedPath(bean.getRunDirectory())); if (!fdir.exists()) { MessageDialog.openConfirm(getSite().getShell(), "Directory Not There", "The directory '" + bean.getRunDirectory() + "' has been moved or deleted.\n\nPlease contact your support representative."); return; } if (Util.isWindowsOS()) { // Open inside DAWN final String dir = fdir.getAbsolutePath(); IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry() .getDefaultEditor(dir + "/fred.html"); final IEditorInput edInput = Util.getExternalFileStoreEditorInput(dir); page.openEditor(edInput, desc.getId()); } else { // Linux cannot be relied on to open the browser on a directory. Util.browse(fdir); } } catch (Exception e1) { ErrorDialog.openError(getSite().getShell(), "Internal Error", "Cannot open " + bean.getRunDirectory() + ".\n\nPlease contact your support representative.", new Status(IStatus.ERROR, Activator.PLUGIN_ID, e1.getMessage())); } } protected void editSelection() { final StatusBean bean = getSelection(); if (bean == null) return; if (bean.getStatus() != org.eclipse.scanning.api.event.status.Status.SUBMITTED) { MessageDialog.openConfirm(getSite().getShell(), "Cannot Edit '" + bean.getName() + "'", "The run '" + bean.getName() + "' cannot be edited because it is not waiting to run."); return; } try { final IConfigurationElement[] c = Platform.getExtensionRegistry() .getConfigurationElementsFor("org.eclipse.scanning.api.modifyHandler"); if (c != null) { for (IConfigurationElement i : c) { final IModifyHandler handler = (IModifyHandler) i.createExecutableExtension("class"); handler.init(service, createConsumerConfiguration()); if (handler.isHandled(bean)) { boolean ok = handler.modify(bean); if (ok) return; } } } } catch (Exception ne) { ne.printStackTrace(); ErrorDialog.openError(getSite().getShell(), "Internal Error", "Cannot modify " + bean.getRunDirectory() + " normally.\n\nPlease contact your support representative.", new Status(IStatus.ERROR, Activator.PLUGIN_ID, ne.getMessage())); return; } MessageDialog.openConfirm(getSite().getShell(), "Cannot Edit '" + bean.getName() + "'", "There are no editers registered for '" + bean.getName() + "'\n\nPlease contact your support representative."); } protected void rerunSelection() { final StatusBean bean = getSelection(); if (bean == null) return; try { final IConfigurationElement[] c = Platform.getExtensionRegistry() .getConfigurationElementsFor("org.eclipse.scanning.api.rerunHandler"); if (c != null) { for (IConfigurationElement i : c) { final IRerunHandler handler = (IRerunHandler) i.createExecutableExtension("class"); handler.init(service, createConsumerConfiguration()); if (handler.isHandled(bean)) { final StatusBean copy = bean.getClass().newInstance(); copy.merge(bean); copy.setUniqueId(UUID.randomUUID().toString()); copy.setStatus(org.eclipse.scanning.api.event.status.Status.SUBMITTED); copy.setSubmissionTime(System.currentTimeMillis()); boolean ok = handler.run(copy); if (ok) return; } } } } catch (Exception ne) { ne.printStackTrace(); ErrorDialog.openError(getSite().getShell(), "Internal Error", "Cannot rerun " + bean.getRunDirectory() + " normally.\n\nPlease contact your support representative.", new Status(IStatus.ERROR, Activator.PLUGIN_ID, ne.getMessage())); return; } // If we have not already handled this rerun, it is possible to call a generic one. rerun(bean); } private ConsumerConfiguration createConsumerConfiguration() throws Exception { return new ConsumerConfiguration(getUri(), getSubmissionQueueName(), getTopicName(), getQueueName()); } private void rerun(StatusBean bean) { try { final DateFormat format = DateFormat.getDateTimeInstance(); boolean ok = MessageDialog.openQuestion(getViewSite().getShell(), "Confirm resubmission " + bean.getName(), "Are you sure you want to rerun " + bean.getName() + " submitted on " + format.format(new Date(bean.getSubmissionTime())) + "?"); if (!ok) return; final StatusBean copy = bean.getClass().newInstance(); copy.merge(bean); copy.setUniqueId(UUID.randomUUID().toString()); copy.setMessage("Rerun of " + bean.getName()); queueConnection.submit(copy, true); reconnect(); } catch (Exception e) { ErrorDialog.openError(getViewSite().getShell(), "Cannot rerun " + bean.getName(), "Cannot rerun " + bean.getName() + "\n\nPlease contact your support representative.", new Status(IStatus.ERROR, "org.eclipse.scanning.event.ui", e.getMessage())); } } public void refresh() { reconnect(); updateSelected(); } protected void reconnect() { try { updateQueue(getUri()); } catch (Exception e) { logger.error("Cannot resolve uri for activemq server of " + getSecondaryIdAttribute("uri")); } } private IContentProvider createContentProvider() { return new IStructuredContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { queue = (Map<String, StatusBean>) newInput; } @Override public void dispose() { if (queue != null) queue.clear(); } @Override public Object[] getElements(Object inputElement) { if (queue == null) return new StatusBean[] { StatusBean.EMPTY }; final List<StatusBean> retained = new ArrayList<StatusBean>(queue.values()); // This preference is not secure people could hack DAWN to do this. if (!Boolean.getBoolean("org.dawnsci.commandserver.ui.view.showWholeQueue")) { // Old fashioned loop. In Java8 we will use a predicate... final String userName = getUserName(); for (Iterator it = retained.iterator(); it.hasNext();) { StatusBean statusBean = (StatusBean) it.next(); if (statusBean.getUserName() == null) continue; if (!showEntireQueue) { if (!userName.equals(statusBean.getUserName())) it.remove(); } } // This form of filtering is not at all secure because we // give the full list of the queue to the clients. } return retained.toArray(new StatusBean[retained.size()]); } }; } protected StatusBean getSelection() { final ISelection sel = viewer.getSelection(); if (sel instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) sel; if (ss.size() > 0) return (StatusBean) ss.getFirstElement(); } return null; } /** * Read Queue and return in submission order. * @param uri * @return * @throws Exception */ protected synchronized void updateQueue(final URI uri) { final Job queueJob = new Job("Connect and read queue") { @Override protected IStatus run(IProgressMonitor monitor) { try { monitor.beginTask("Connect to command server", 10); monitor.worked(1); queueConnection.setBeanClass(getBeanClass()); List<StatusBean> runningList = queueConnection.getQueue(getQueueName(), "submissionTime"); // Submission order monitor.worked(1); List<StatusBean> submittedList = queueConnection.getQueue(getSubmissionQueueName(), null); Collections.reverse(submittedList); // The list comes out with the head @ 0 but we have the last submitted at 0 in our table. monitor.worked(1); // We reverse the queue because it comes out date ascending and we // want newest submissions first. final Map<String, StatusBean> ret = new LinkedHashMap<String, StatusBean>(); for (StatusBean bean : submittedList) { ret.put(bean.getUniqueId(), bean); } monitor.worked(1); for (StatusBean bean : runningList) { ret.put(bean.getUniqueId(), bean); } monitor.worked(1); getSite().getShell().getDisplay().syncExec(new Runnable() { public void run() { viewer.setInput(ret); viewer.refresh(); } }); monitor.done(); return Status.OK_STATUS; } catch (final Exception e) { e.printStackTrace(); monitor.done(); logger.error("Updating changed bean from topic", e); getSite().getShell().getDisplay().syncExec(new Runnable() { public void run() { ErrorDialog.openError(getViewSite().getShell(), "Cannot connect to queue", "The command server is unavailable.\n\nPlease contact your support representative.", new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage())); } }); return Status.CANCEL_STATUS; } } }; queueJob.setPriority(Job.INTERACTIVE); queueJob.setUser(true); queueJob.schedule(); } private Class<StatusBean> getBeanClass() { String beanBundleName = getSecondaryIdAttribute("beanBundleName"); String beanClassName = getSecondaryIdAttribute("beanClassName"); try { Bundle bundle = Platform.getBundle(beanBundleName); return (Class<StatusBean>) bundle.loadClass(beanClassName); } catch (Exception ne) { logger.error("Cannot get class " + beanClassName + ". Defaulting to StatusBean. This will probably not work though.", ne); return StatusBean.class; } } protected void createColumns() { final TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT); name.getColumn().setText("Name"); name.getColumn().setWidth(260); name.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { return ((StatusBean) element).getName(); } }); final TableViewerColumn status = new TableViewerColumn(viewer, SWT.LEFT); status.getColumn().setText("Status"); status.getColumn().setWidth(140); status.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { return ((StatusBean) element).getStatus().toString(); } }); final TableViewerColumn pc = new TableViewerColumn(viewer, SWT.CENTER); pc.getColumn().setText("Complete (%)"); pc.getColumn().setWidth(120); pc.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { return NumberFormat.getPercentInstance() .format(((StatusBean) element).getPercentComplete() / 100d); } catch (Exception ne) { return "-"; } } }); final TableViewerColumn submittedDate = new TableViewerColumn(viewer, SWT.CENTER); submittedDate.getColumn().setText("Date Submitted"); submittedDate.getColumn().setWidth(150); submittedDate.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { return DateFormat.getDateTimeInstance() .format(new Date(((StatusBean) element).getSubmissionTime())); } catch (Exception e) { return e.getMessage(); } } }); final TableViewerColumn message = new TableViewerColumn(viewer, SWT.LEFT); message.getColumn().setText("Message"); message.getColumn().setWidth(150); message.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { return ((StatusBean) element).getMessage(); } catch (Exception e) { return e.getMessage(); } } }); final TableViewerColumn location = new TableViewerColumn(viewer, SWT.LEFT); location.getColumn().setText("Location"); location.getColumn().setWidth(300); location.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { final StatusBean bean = (StatusBean) element; return bean.getRunDirectory(); } catch (Exception e) { return e.getMessage(); } } public Color getForeground(Object element) { return getSite().getShell().getDisplay().getSystemColor(SWT.COLOR_BLUE); } }); final TableViewerColumn host = new TableViewerColumn(viewer, SWT.CENTER); host.getColumn().setText("Host"); host.getColumn().setWidth(150); host.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { return ((StatusBean) element).getHostName(); } catch (Exception e) { return e.getMessage(); } } }); final TableViewerColumn user = new TableViewerColumn(viewer, SWT.CENTER); user.getColumn().setText("User Name"); user.getColumn().setWidth(150); user.setLabelProvider(new ColumnLabelProvider() { public String getText(Object element) { try { return ((StatusBean) element).getUserName(); } catch (Exception e) { return e.getMessage(); } } }); MouseMoveListener cursorListener = new MouseMoveListener() { @Override public void mouseMove(MouseEvent e) { Point pt = new Point(e.x, e.y); TableItem item = viewer.getTable().getItem(pt); if (item == null) { viewer.getTable().setCursor(null); return; } Rectangle rect = item.getBounds(5); if (rect.contains(pt)) { viewer.getTable().setCursor(Display.getDefault().getSystemCursor(SWT.CURSOR_HAND)); } else { viewer.getTable().setCursor(null); } } }; viewer.getTable().addMouseMoveListener(cursorListener); MouseAdapter mouseClick = new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { Point pt = new Point(e.x, e.y); TableItem item = viewer.getTable().getItem(pt); if (item == null) return; Rectangle rect = item.getBounds(5); if (rect.contains(pt)) { final StatusBean bean = (StatusBean) item.getData(); openResults(bean); } } }; viewer.getTable().addMouseListener(mouseClick); } @Override public void setFocus() { if (!viewer.getTable().isDisposed()) { viewer.getTable().setFocus(); } } public static String createId(final String beanBundleName, final String beanClassName, final String queueName, final String topicName, final String submissionQueueName) { final StringBuilder buf = new StringBuilder(); buf.append(ID); buf.append(":"); buf.append(createSecondaryId(beanBundleName, beanClassName, queueName, topicName, submissionQueueName)); return buf.toString(); } public static String createId(final String uri, final String beanBundleName, final String beanClassName, final String queueName, final String topicName, final String submissionQueueName) { final StringBuilder buf = new StringBuilder(); buf.append(ID); buf.append(":"); buf.append( createSecondaryId(uri, beanBundleName, beanClassName, queueName, topicName, submissionQueueName)); return buf.toString(); } }