/** * Copyright (c) 2011, 2012 Gunnar Wagenknecht and others. * 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: * Gunnar Wagenknecht - initial API and implementation */ package org.eclipse.gyrex.admin.ui.jobs.internal; import org.eclipse.gyrex.admin.ui.internal.helper.SwtUtil; import org.eclipse.gyrex.admin.ui.internal.widgets.AdminPageWithTree; import org.eclipse.gyrex.admin.ui.internal.widgets.Infobox; import org.eclipse.gyrex.admin.ui.internal.widgets.NonBlockingMessageDialogs; import org.eclipse.gyrex.admin.ui.internal.wizards.NonBlockingWizardDialog; import org.eclipse.gyrex.context.IRuntimeContext; import org.eclipse.gyrex.context.registry.IRuntimeContextRegistry; import org.eclipse.gyrex.jobs.IJob; import org.eclipse.gyrex.jobs.internal.JobsActivator; import org.eclipse.gyrex.jobs.internal.schedules.ScheduleEntryImpl; import org.eclipse.gyrex.jobs.internal.schedules.ScheduleImpl; import org.eclipse.gyrex.jobs.internal.schedules.ScheduleManagerImpl; import org.eclipse.gyrex.jobs.internal.schedules.ScheduleStore; import org.eclipse.gyrex.jobs.internal.util.ContextHashUtil; import org.eclipse.gyrex.jobs.manager.IJobManager; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jface.util.Policy; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.window.Window; import org.eclipse.rap.rwt.widgets.DialogCallback; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.osgi.service.prefs.BackingStoreException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.UnhandledException; public class ScheduleEntriesPage extends AdminPageWithTree { public static final String ID = "schedule-entries"; private static final int COLUMN_ID = 0; private static final int COLUMN_TYPE = 1; private static final int COLUMN_CRON = 2; private static final int COLUMN_PRECEDINGS = 3; private static final int COLUMN_LAST_RESULT = 4; private Button addButton; private Button editButton; private Button removeButton; private Button enableButton; private Button disableButton; private ScheduleImpl schedule; public ScheduleEntriesPage() { super(5); setTitle("Schedule Entries"); setTitleToolTip("Edit a schedule and its entries for executing background tasks."); } void addButtonPressed() { editOrAddScheduleEntry(null); } @Override protected void createButtons(final Composite parent) { addButton = createButton(parent, "New..."); addButton.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { addButtonPressed(); } }); editButton = createButton(parent, "Edit..."); editButton.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { editButtonPressed(); } }); removeButton = createButton(parent, "Remove"); removeButton.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { removeButtonPressed(); } }); createButtonSeparator(parent); enableButton = createButton(parent, "Enable"); enableButton.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { enableButtonPressed(); } }); disableButton = createButton(parent, "Disable"); disableButton.addSelectionListener(new SelectionAdapter() { private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { disableButtonPressed(); } }); } @Override protected ITreeContentProvider createContentProvider() { return new ScheduleEntriesContentProvider(); } @Override protected Control createHeader(final Composite parent) { final Infobox infobox = new Infobox(parent); infobox.addHeading("Schedule Entries"); infobox.addParagraph("A schedule is composed of schedule entries. They define, what and how a background task should run. They can have a cron expression and/or a dependency on other entries in the same schedule."); infobox.addLink("Back to <a>schedules list</a>", new SelectionAdapter() { /** serialVersionUID */ private static final long serialVersionUID = 1L; @Override public void widgetSelected(final SelectionEvent e) { openSchedulesPage(); } }); return infobox; } void disableButtonPressed() { final ScheduleEntryImpl scheduleEntry = getSelectedScheduleEntry(); if (scheduleEntry == null) return; try { scheduleEntry.setEnabled(false); scheduleEntry.getSchedule().save(); } catch (final BackingStoreException e) { Policy.getStatusHandler().show(new Status(IStatus.ERROR, JobsUiActivator.SYMBOLIC_NAME, "Unable to activate schedule.", e), "Error"); } getTreeViewer().refresh(scheduleEntry); updateButtons(); } void editButtonPressed() { editOrAddScheduleEntry(getSelectedScheduleEntry()); } private void editOrAddScheduleEntry(final ScheduleEntryImpl entryToEdit) { if (schedule.isEnabled()) { NonBlockingMessageDialogs.openInformation(SwtUtil.getShell(getTreeViewer().getTree()), "Active Schedule", "The schedule is enabled and cannot be modified. Please disable it first!", null); return; } final NonBlockingWizardDialog dialog = new NonBlockingWizardDialog(SwtUtil.getShell(getTreeViewer().getTree()), new ScheduleEntryWizard(getSchedule(), entryToEdit)); dialog.openNonBlocking(new DialogCallback() { private static final long serialVersionUID = 1L; @Override public void dialogClosed(final int returnCode) { if (returnCode == Window.OK) { refresh(); } } }); } void enableButtonPressed() { final ScheduleEntryImpl scheduleEntry = getSelectedScheduleEntry(); if (scheduleEntry == null) return; try { scheduleEntry.setEnabled(true); scheduleEntry.getSchedule().save(); } catch (final BackingStoreException e) { Policy.getStatusHandler().show(new Status(IStatus.ERROR, JobsUiActivator.SYMBOLIC_NAME, "Unable to activate schedule.", e), "Error"); } getTreeViewer().refresh(scheduleEntry); updateButtons(); } @Override protected String getColumnLabel(final int column) { switch (column) { case COLUMN_ID: return "Entry"; case COLUMN_TYPE: return "Task"; case COLUMN_CRON: return "Cron Exp."; case COLUMN_PRECEDINGS: return "Precedings"; case COLUMN_LAST_RESULT: return "Last Run"; default: return StringUtils.EMPTY; } } @Override protected Image getElementImage(final Object element, final int column) { if ((element instanceof ScheduleEntryImpl)) { if (column == COLUMN_ID) if (((ScheduleEntryImpl) element).isEnabled()) return JobsUiImages.getImage(JobsUiImages.IMG_OBJ_ACTIVE); else return JobsUiImages.getImage(JobsUiImages.IMG_OBJ_INACTIVE); else if (column == COLUMN_LAST_RESULT) return getLastResultImage((ScheduleEntryImpl) element); } return null; } @Override protected String getElementLabel(final Object element, final int column) { if (element instanceof ScheduleEntryImpl) { final ScheduleEntryImpl entry = (ScheduleEntryImpl) element; switch (column) { case COLUMN_ID: return entry.getId(); case COLUMN_TYPE: return getName(entry); case COLUMN_CRON: return entry.getCronExpression(); case COLUMN_PRECEDINGS: return StringUtils.join(entry.getPrecedingEntries(), ", "); case COLUMN_LAST_RESULT: if (null == getLastResultImage(entry)) return getLastResult(entry); else return null; default: return null; } } return null; } String getLastResult(final ScheduleEntryImpl entry) { final IRuntimeContext ctx = JobsUiActivator.getInstance().getService(IRuntimeContextRegistry.class).get(schedule.getContextPath()); if (ctx != null) { final IJobManager jobManager = ctx.get(IJobManager.class); if (jobManager != null) { final IJob job = jobManager.getJob(entry.getJobId()); if (job != null) { final IStatus result = job.getLastResult(); if (result != null) { if (result.isOK()) return "OK"; else if (result.matches(IStatus.CANCEL)) return "aborted"; else if (result.matches(IStatus.ERROR)) return "failed"; else if (result.matches(IStatus.WARNING)) return "with warnings"; else if (result.matches(IStatus.INFO)) return "OK"; } } } } return "n/a"; }; private Image getLastResultImage(final ScheduleEntryImpl entry) { final IRuntimeContext ctx = JobsUiActivator.getInstance().getService(IRuntimeContextRegistry.class).get(schedule.getContextPath()); if (ctx != null) { final IJobManager jobManager = ctx.get(IJobManager.class); if (jobManager != null) { final IJob job = jobManager.getJob(entry.getJobId()); if (job != null) { final IStatus result = job.getLastResult(); if (result != null) { if (result.isOK()) return null; else if (result.matches(IStatus.CANCEL)) return null; else if (result.matches(IStatus.ERROR)) return JobsUiImages.getImage(JobsUiImages.IMG_OBJ_ERROR_RESULT); else if (result.matches(IStatus.WARNING)) return JobsUiImages.getImage(JobsUiImages.IMG_OBJ_WARN_RESULT); else if (result.matches(IStatus.INFO)) return null; } } } } return null; } private String getName(final ScheduleEntryImpl entry) { final String name = JobsActivator.getInstance().getJobProviderRegistry().getName(entry.getJobTypeId()); if (StringUtils.isNotBlank(name)) return name; return "unknown (" + entry.getJobTypeId() + ")"; } public ScheduleImpl getSchedule() { return schedule; } private ScheduleEntryImpl getSelectedScheduleEntry() { final IStructuredSelection selection = (IStructuredSelection) getTreeViewer().getSelection(); if (!selection.isEmpty() && (selection.getFirstElement() instanceof ScheduleEntryImpl)) return (ScheduleEntryImpl) selection.getFirstElement(); return null; } @Override protected Object getViewerInput() { return schedule; } @Override protected boolean isColumnSortable(final int column) { return false; } protected void openSchedulesPage() { getAdminUi().openPage(BackgroundTasksPage.ID); } @Override protected void openSelectedElement() { editOrAddScheduleEntry(getSelectedScheduleEntry()); } @Override protected void refresh() { try { getSchedule().load(); } catch (final BackingStoreException e) { Policy.getStatusHandler().show(new Status(IStatus.ERROR, JobsUiActivator.SYMBOLIC_NAME, "Error loading schedule.", e), "Error"); } getTreeViewer().refresh(); } void removeButtonPressed() { final ScheduleEntryImpl scheduleEntry = getSelectedScheduleEntry(); if (scheduleEntry == null) return; NonBlockingMessageDialogs.openQuestion(SwtUtil.getShell(getTreeViewer().getTree()), "Remove selected Schedule entry ", String.format("Do you really want to delete schedule entry %s?", scheduleEntry.getId()), new DialogCallback() { /** serialVersionUID */ private static final long serialVersionUID = 1L; @Override public void dialogClosed(final int returnCode) { if (returnCode != Window.OK) return; try { final ScheduleImpl schedule = scheduleEntry.getSchedule(); schedule.removeEntry(scheduleEntry.getId()); schedule.save(); } catch (final Exception | LinkageError | AssertionError e) { Policy.getStatusHandler().show(new Status(IStatus.ERROR, JobsUiActivator.SYMBOLIC_NAME, "Unable to activate schedule.", e), "Error"); } refresh(); updateButtons(); } }); } @Override public void setArguments(final String[] args) { super.setArguments(args); if (args.length >= 3) { final String contextPath = args[1]; final String scheduleId = args[2]; final String storageKey = new ContextHashUtil(new Path(contextPath)).toInternalId(scheduleId); try { final ScheduleImpl schedule = ScheduleStore.load(storageKey, ScheduleManagerImpl.getExternalId(storageKey), false); if (schedule != null) { setSchedule(schedule); } else throw new IllegalArgumentException(String.format("Schedule %s not found in context %s", scheduleId, contextPath)); } catch (final BackingStoreException e) { throw new UnhandledException(e); } } } public void setSchedule(final ScheduleImpl schedule) { this.schedule = schedule; setTitle("Schedule Entries of Schedule " + schedule.getId()); } @Override protected void updateButtons() { if (getSchedule().isEnabled()) { // disable all buttons when schedule is enabled addButton.setEnabled(false); editButton.setEnabled(false); removeButton.setEnabled(false); enableButton.setEnabled(false); disableButton.setEnabled(false); return; } final int selectedElementsCount = ((IStructuredSelection) getTreeViewer().getSelection()).size(); if (selectedElementsCount == 0) { addButton.setEnabled(true); editButton.setEnabled(false); removeButton.setEnabled(false); enableButton.setEnabled(false); disableButton.setEnabled(false); return; } addButton.setEnabled(true); editButton.setEnabled(selectedElementsCount == 1); removeButton.setEnabled(selectedElementsCount == 1); final ScheduleEntryImpl selectedScheduleEntry = getSelectedScheduleEntry(); if (selectedScheduleEntry != null) { if (selectedScheduleEntry.isEnabled()) { enableButton.setEnabled(false); disableButton.setEnabled(true); } else { enableButton.setEnabled(true); disableButton.setEnabled(false); } } } }