diff --git a/plugins/org.eclipse.dd.examples.dsf/plugin.xml b/plugins/org.eclipse.dd.examples.dsf/plugin.xml index 22ed17e9762..d6326a29615 100644 --- a/plugins/org.eclipse.dd.examples.dsf/plugin.xml +++ b/plugins/org.eclipse.dd.examples.dsf/plugin.xml @@ -13,7 +13,7 @@ icon="icons/timer.gif" category="org.eclipse.dd.examples.dsf" class="org.eclipse.dd.examples.dsf.timers.TimersView" - id="org.eclipse.dd.dsf.examples.model.TimersAlarmsView"> + id="org.eclipse.dd.examples.dsf.TimersView"> rm) { - rm.setStatus(new Status(IStatus.OK, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ rm.done(); } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmService.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmService.java index ec4ef5c0e6b..830580c4e57 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmService.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmService.java @@ -11,163 +11,114 @@ package org.eclipse.dd.examples.dsf.timers; import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.TreeMap; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.AbstractDMContext; import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.datamodel.IDMContext; -import org.eclipse.dd.dsf.datamodel.IDMData; -import org.eclipse.dd.dsf.datamodel.IDMService; import org.eclipse.dd.dsf.service.AbstractDsfService; import org.eclipse.dd.dsf.service.DsfServiceEventHandler; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerData; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerTickEvent; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimerTickDMEvent; import org.osgi.framework.BundleContext; /** - * Alarm service tracks a set of alarm objects which are occacionally - * triggered by the timers from the TimerService. + * The alarm service tracks triggers and alarms. Triggers have a specified + * value and can be created and removed independently. Alarms are created + * for a specific timer and a trigger, and can indicate whether an alarm is + * triggered. *

* This service depends on the TimerService, so the TimerService has to be - * running before this service is initialized. However, the alarm objects - * themeselves do not depend on the timers, they can be listed, created, - * removed without any timers present. So a separate context object exists - * to track alarm status, which requires both an alarm and a timer in order - * to exist. + * initialized before this service is initialized. + *

*/ public class AlarmService extends AbstractDsfService - implements IDMService { - /** - * Event indicating that the list of alarms is changed and the clients - * which display alarms should re-query this list. - */ - public class AlarmsChangedEvent extends AbstractDMEvent { - AlarmsChangedEvent() { super(fAlarmsContext); } - } + /** Event indicating that the list of triggers is changed. */ + @Immutable + public static class TriggersChangedEvent {} - /** - * Context representing an alarm tracked by this service. - */ - public static class AlarmDMC extends AbstractDMContext { + /** Context representing an alarm tracked by this service. */ + @Immutable + public static class TriggerDMContext extends AbstractDMContext { /** Alarm number, also index into alarm map */ - final int fAlarm; + final int fNumber; - public AlarmDMC(AlarmService service, int alarm) { - super(service, new IDMContext[] { service.fAlarmsContext }); - fAlarm = alarm; + private TriggerDMContext(String sessionId, int number) { + super(sessionId, new IDMContext[0]); + fNumber = number; } @Override public boolean equals(Object other) { - return baseEquals(other) && ((AlarmDMC)other).fAlarm == fAlarm; + return baseEquals(other) && + ((TriggerDMContext)other).fNumber == fNumber; + } + + public int getTriggerNumber() { + return fNumber; } @Override - public int hashCode() { return baseHashCode() + fAlarm; } + public int hashCode() { + return baseHashCode() + fNumber; + } + @Override - public String toString() { return baseToString() + ".alarm[" + fAlarm + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + public String toString() { + return baseToString() + ".trigger[" + fNumber + "]"; + } } - /** - * Data object containing information about the alarm. This object - * references internal service data, so it has to guard agains this data - * being obsolete. - */ - public class AlarmData implements IDMData { - private int fAlarmNumber; - - AlarmData(int alarmNumber) { fAlarmNumber = alarmNumber; } - public boolean isValid() { return fAlarms.containsKey(fAlarmNumber); } - public int getAlarmNumber() { return fAlarmNumber; } - - public int getTriggeringValue() { - if (!isValid()) return -1; - return fAlarms.get(fAlarmNumber); - } - } - /** * Context representing the "triggered" status of an alarm with respect to - * a specific timer. Having this object separate from the alarm itself - * allows the alarm object to exist independently of the timers. + * a specific timer. */ - public class AlarmStatusContext extends AbstractDMContext { - /** - * An alarm status requires both a timer and alarm context, both of which - * become parents of the status context. - */ - public AlarmStatusContext(AbstractDsfService service, TimerDMC timerCtx, AlarmDMC alarmCtx) { - super(service.getSession().getId(), new IDMContext[] { timerCtx, alarmCtx }); + @Immutable + public static class AlarmDMContext extends AbstractDMContext { + // An alarm requires both a timer and alarm context, both of which + // become parents of the alarm context. + // Note: beyond the parent contexts this context does not contain + // any other data, because no other data is needed. + private AlarmDMContext(String sessionId, + TimerDMContext timerCtx, TriggerDMContext alarmCtx) + { + super(sessionId, new IDMContext[] { timerCtx, alarmCtx }); } @Override public boolean equals(Object other) { return baseEquals(other); } + @Override - public int hashCode() { return baseHashCode(); } + public int hashCode() { return baseHashCode(); } + @Override public String toString() { - return baseToString() + ":alarm_status"; //$NON-NLS-1$ + return baseToString() + ":alarm"; //$NON-NLS-1$ } } /** - * Data about alarm status. No surprises here. - * + * Event indicating that an alarm has been triggered by a timer. */ - public class AlarmStatusData implements IDMData { - private boolean fIsTriggered; - - public boolean isValid() { return true; } - AlarmStatusData(boolean triggered) { fIsTriggered = triggered; } - public boolean isTriggered() { return fIsTriggered; } - } - - /** - * Event indicating that an alarm has been triggered by a timer. The - * status context object's parents indicate which alarm and timer are - * involved. - */ - public class AlarmTriggeredEvent extends AbstractDMEvent { - public AlarmTriggeredEvent(AlarmStatusContext context) { + public class AlarmTriggeredEvent extends AbstractDMEvent { + public AlarmTriggeredEvent(AlarmDMContext context) { super(context); } } + private int fTriggerNumberCounter = 1; + private Map fTriggers = + new LinkedHashMap(); - /** Parent context for all alarms */ - private final IDMContext fAlarmsContext; - - /** Counter for generating alarm numbers */ - private int fAlarmCounter = 1; - - /** Map holding the alarms */ - private Map fAlarms = new TreeMap(); - - /** Constructor requires only the session for this service */ AlarmService(DsfSession session) { super(session); - fAlarmsContext = new AbstractDMContext(this, new IDMContext[0]) { - private final Object fHashObject = new Object(); - - @Override - public boolean equals(Object obj) { return (this == obj); }; - - @Override - public int hashCode() { return fHashObject.hashCode(); } - - @Override - public String toString() { return "#alarms"; } //$NON-NLS-1$ - }; } @Override @@ -181,17 +132,20 @@ public class AlarmService extends AbstractDsfService new RequestMonitor(getExecutor(), requestMonitor) { @Override protected void handleOK() { + // After super-class is finished initializing + // perform TimerService initialization. doInitialize(requestMonitor); }}); } - /** - * Initialization routine registers the service, and adds it as a listener - * to service events. - */ private void doInitialize(RequestMonitor requestMonitor) { + // Add this class as a listener for service events, in order to receive + // TimerTickEvent events. getSession().addServiceEventListener(this, null); + + // Register service register(new String[]{AlarmService.class.getName()}, new Hashtable()); + requestMonitor.done(); } @@ -204,158 +158,95 @@ public class AlarmService extends AbstractDsfService public boolean isValid() { return true; } - @SuppressWarnings("unchecked") - public void getModelData(IDMContext dmc, DataRequestMonitor rm) { - if (dmc instanceof AlarmDMC) { - getAlarmData((AlarmDMC)dmc, (DataRequestMonitor)rm); - return; - } else if (dmc instanceof AlarmStatusContext) { - getAlarmStatusData((AlarmStatusContext)dmc, (DataRequestMonitor)rm); - return; - } else if (dmc == fAlarmsContext) { - ((DataRequestMonitor)rm).setData(this); - } else { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ - } - rm.done(); - } - - /** - * Listener for timer ticks events. If a timer triggers an alarm, this - * service needs to issue an alarm triggered event. - * @param event - */ @DsfServiceEventHandler - public void eventDispatched(TimerTickEvent event) { - final TimerDMC timerContext = event.getDMContext(); + public void eventDispatched(TimerTickDMEvent event) { + final TimerDMContext timerContext = event.getDMContext(); - getServicesTracker().getService(TimerService.class).getTimerData( - event.getDMContext(), - new DataRequestMonitor(getExecutor(), null) { - @Override - protected void handleCompleted() { - if (!getStatus().isOK()) return; - checkAlarmsForTimer(timerContext, getData().getTimerValue()); - } - @Override public String toString() { return "Got timer data: " + getData(); } //$NON-NLS-1$ - }); + int timerValue = getServicesTracker().getService(TimerService.class). + getTimerValue(event.getDMContext()); + + // If a timer triggers an alarm, this service needs to issue an alarm + // triggered event. + checkAlarmsForTimer(timerContext, timerValue); } - /** - * Checks the existing alarms for whether they are triggered by given timer. - * @param timerContext Context of the timer that is changed. - * @param timerValue Current value of the timer. - */ - private void checkAlarmsForTimer(TimerDMC timerContext, int timerValue) { - for (Map.Entry entry : fAlarms.entrySet()) { + private void checkAlarmsForTimer(TimerDMContext timerContext, int timerValue) { + // Check the existing alarms for whether they are triggered by given + // timer. + for (Map.Entry entry : fTriggers.entrySet()) { if (timerValue == entry.getValue()) { - getSession().dispatchEvent(new AlarmTriggeredEvent( - new AlarmStatusContext(this, timerContext, new AlarmDMC(this, entry.getKey()))), - getProperties()); + // Generate the AlarmTriggeredEvent + AlarmDMContext alarmCtx = new AlarmDMContext( + getSession().getId(), timerContext, entry.getKey()); + getSession().dispatchEvent( + new AlarmTriggeredEvent(alarmCtx), getProperties()); } } } - /** - * Retrieves the list of alarm contexts. - * - *
Note: this method doesn't need to be asynchronous, because all the - * data is stored locally. But using an asynchronous method makes this a - * more applicable example. - * - * @param rm Return data token. - */ - public void getAlarms(DataRequestMonitor rm) { - AlarmDMC[] alarmContexts = new AlarmDMC[fAlarms.size()]; - int i = 0; - for (int alarm : fAlarms.keySet()) { - alarmContexts[i++] = new AlarmDMC(this, alarm); + /** Returns the list of triggers. */ + public TriggerDMContext[] getTriggers() { + return fTriggers.keySet().toArray(new TriggerDMContext[fTriggers.size()]); + } + + /** Returns the trigger value. */ + public int getTriggerValue(TriggerDMContext alarmCtx) { + Integer value = fTriggers.get(alarmCtx); + if (value != null) { + return value; + } else { + return -1; } - rm.setData(alarmContexts); - rm.done(); } - /** - * Retrieves the data object for given alarm context. - * - *
Note: likewise this method doesn't need to be asynchronous. - */ - public void getAlarmData(AlarmDMC alarmCtx, DataRequestMonitor rm) { - if (!fAlarms.containsKey(alarmCtx.fAlarm)) { - rm.setStatus(new Status( - IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Alarm context invalid", null)); //$NON-NLS-1$ - rm.done(); - return; + /** Returns the alarm context for given timer and trigger contexts. */ + public AlarmDMContext getAlarmS(TriggerDMContext alarmCtx, TimerDMContext timerCtx) { + return new AlarmDMContext(getSession().getId(), timerCtx, alarmCtx); + } + + /** Returns true if the given alarm is triggered */ + public boolean isAlarmTriggered(AlarmDMContext alarmCtx) { + // Extract the timer and trigger contexts. They should always be part + // of the alarm. + TimerService.TimerDMContext timerCtx = DMContexts.getAncestorOfType( + alarmCtx, TimerService.TimerDMContext.class); + TriggerDMContext triggerCtx = DMContexts.getAncestorOfType( + alarmCtx, TriggerDMContext.class); + + assert triggerCtx != null && timerCtx != null; + + // Find the trigger and check whether the timers value has surpassed it. + if (fTriggers.containsKey(triggerCtx)) { + int timerValue = getServicesTracker().getService(TimerService.class). + getTimerValue(timerCtx); + + return timerValue >= fTriggers.get(triggerCtx); } - rm.setData(new AlarmData(alarmCtx.fAlarm)); - rm.done(); - } - - /** - * Returns the alarm status context object, for given timer and alarms. - * - *
Note: this method is synchronous... for variety. - */ - public AlarmStatusContext getAlarmStatus(AlarmDMC alarmCtx, TimerDMC timerCtx) { - return new AlarmStatusContext(this, timerCtx, alarmCtx); - } - - /** - * Returns the data object for given alarm status object. - */ - public void getAlarmStatusData(AlarmStatusContext alarmStatusCtx, final DataRequestMonitor rm) { - final TimerService.TimerDMC timerCtx = DMContexts.getAncestorOfType( - alarmStatusCtx, TimerService.TimerDMC.class); - final AlarmDMC alarmCtx = DMContexts.getAncestorOfType( - alarmStatusCtx, AlarmDMC.class); - - assert alarmCtx != null && timerCtx != null; - getServicesTracker().getService(TimerService.class).getTimerData( - timerCtx, - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleOK() { - if (!fAlarms.containsKey(alarmCtx.fAlarm)) { - rm.setStatus(new Status( - IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Alarm context invalid", null)); //$NON-NLS-1$ - rm.done(); - return; - } - boolean isTriggered = getData().getTimerValue() >= fAlarms.get(alarmCtx.fAlarm); - rm.setData(new AlarmStatusData(isTriggered)); - rm.done(); - } - }); + return false; } - /** - * Creates a new alarm object with given value. - * @return context of the new alarm. - */ - public AlarmDMC createAlarm(int value) { - int newAlarm = fAlarmCounter++; - fAlarms.put(newAlarm, value); - getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties()); - return new AlarmDMC(this, newAlarm); + /** Creates a new alarm object with given value. */ + public TriggerDMContext createTrigger(int value) { + TriggerDMContext triggerCtx = + new TriggerDMContext(getSession().getId(), fTriggerNumberCounter++); + fTriggers.put(triggerCtx, value); + getSession().dispatchEvent(new TriggersChangedEvent(), getProperties()); + return triggerCtx; } /** Removes given alarm from service. */ - public void deleteAlarm(AlarmDMC alarmCtx) { - fAlarms.remove(alarmCtx.fAlarm); - getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties()); + public void deleteTrigger(TriggerDMContext alarmCtx) { + fTriggers.remove(alarmCtx); + getSession().dispatchEvent(new TriggersChangedEvent(), getProperties()); } - /** - * Changes the value of the given alarm. - * @param dmc Alarm to change - * @param newValue New alarm value. - */ - public void setAlarmValue(AlarmDMC dmc, int newValue) { - if (fAlarms.containsKey(dmc.fAlarm)) { - fAlarms.put(dmc.fAlarm, newValue); + /** Changes the value of the given trigger. */ + public void setTriggerValue(TriggerDMContext ctx, int newValue) { + if (fTriggers.containsKey(ctx)) { + fTriggers.put(ctx, newValue); } - getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties()); + getSession().dispatchEvent(new TriggersChangedEvent(), getProperties()); } } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmStatusVMNode.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmStatusVMNode.java deleted file mode 100644 index 7f0213ade34..00000000000 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmStatusVMNode.java +++ /dev/null @@ -1,112 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 Wind River Systems 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: - * Wind River Systems - initial API and implementation - *******************************************************************************/ -package org.eclipse.dd.examples.dsf.timers; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; -import org.eclipse.dd.dsf.concurrent.RequestMonitor; -import org.eclipse.dd.dsf.service.DsfSession; -import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; -import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmStatusContext; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmStatusData; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; -import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; - -/** - * View model node that determines whether an "alarm triggered" indicator is - * shown in the tree. This indicator is only shown if a given alarm is - * triggered for a given timer. - * - * @see AlarmStatusContext - */ -@SuppressWarnings("restriction") -class AlarmStatusVMNode extends AbstractDMVMNode - implements IElementLabelProvider -{ - public AlarmStatusVMNode(AbstractDMVMProvider provider, DsfSession session) { - super(provider, session, AlarmStatusContext.class); - } - - @Override - protected void updateElementsInSessionThread(final IChildrenUpdate update) { - if (!checkService(AlarmService.class, null, update)) return; - if (!checkService(TimerService.class, null, update)) return; - - AlarmDMC alarmDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), AlarmDMC.class); - TimerDMC timerDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMC.class); - if (alarmDmc == null || timerDmc == null) { - update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path")); //$NON-NLS-1$ - update.done(); - return; - } - - // Get the alarm status DMC then check the triggered value to make sure it's triggered. - final AlarmStatusContext alarmStatusDmc = getServicesTracker().getService(AlarmService.class). - getAlarmStatus(alarmDmc, timerDmc); - getServicesTracker().getService(AlarmService.class).getAlarmStatusData( - alarmStatusDmc, - new DataRequestMonitor(getSession().getExecutor(), null) { - @Override - public void handleCompleted() { - if (isDisposed()) return; - if (!getStatus().isOK()) { - update.setStatus(getStatus()); - } else { - if (getData().isTriggered()) { - update.setChild(createVMContext(alarmStatusDmc), 0); - } - } - update.done(); - }}); - } - - public void update(ILabelUpdate[] updates) { - for (ILabelUpdate update : updates) { - update.setLabel("ALARM TRIGGERED", 0); //$NON-NLS-1$ - update.setImageDescriptor( - DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( - DsfExamplesPlugin.IMG_ALARM_TRIGGERED), - 0); - update.done(); - } - } - - - public int getDeltaFlags(Object e) { - // This node generates delta if the timers have changed, or if the - // label has changed. - if (e instanceof AlarmService.AlarmTriggeredEvent) { - return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND; - } - return IModelDelta.NO_CHANGE; - } - - public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) { - // An element is added when and selected upon a triggered event. - // Parent element is also expanded allow element to be selected. - if (e instanceof AlarmService.AlarmTriggeredEvent) { - parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND); - parentDelta.addNode( - createVMContext( ((AlarmService.AlarmTriggeredEvent)e).getDMContext() ), - 0, - IModelDelta.ADDED | IModelDelta.SELECT); - } - requestMonitor.done(); - } -} diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmsVMNode.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmsVMNode.java index 885934bf736..3f86a7825c3 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmsVMNode.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmsVMNode.java @@ -10,203 +10,96 @@ *******************************************************************************/ package org.eclipse.dd.examples.dsf.timers; -import java.text.MessageFormat; -import java.util.concurrent.RejectedExecutionException; - -import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; -import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.service.DsfSession; -import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; -import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider; -import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate; -import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute; -import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo; -import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage; -import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText; -import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmData; +import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMContext; +import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ICellModifier; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.swt.widgets.Composite; - /** - * View model node that defines how alarm DMContexts are displayed in the view. Alarm - * nodes are fairly static, once they are created their label doesn't change. - * @see AlarmDMC + * View model node that determines whether an "alarm triggered" indicator is + * shown in the tree. This indicator is only shown if a given alarm is + * triggered for a given timer. + * + * @see AlarmDMContext */ @SuppressWarnings("restriction") class AlarmsVMNode extends AbstractDMVMNode - implements IElementEditor, IElementPropertiesProvider, IElementLabelProvider + implements IElementLabelProvider { - public static final String PROP_ALARM_NUMBER = "alarmNumber"; //$NON-NLS-1$ - public static final String PROP_ALARM_TRIGGER_VALUE = "alarmTriggerValue"; //$NON-NLS-1$ - - private AlarmCellModifier fAlarmCellModifier; - private PropertyBasedLabelProvider fLabelProvider; - - public AlarmsVMNode(AbstractDMVMProvider provider, DsfSession session) { - super(provider, session, AlarmDMC.class); - - fLabelProvider = new PropertyBasedLabelProvider(); - - LabelColumnInfo idCol = new LabelColumnInfo( - new LabelAttribute[] { - new LabelText(new MessageFormat("Alarm #{0}"), new String[] { PROP_ALARM_NUMBER }), //$NON-NLS-1$ - new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(DsfExamplesPlugin.IMG_ALARM)) - }); - fLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol); - - LabelText valueText = new LabelText(new MessageFormat("{0}"), new String[] { PROP_ALARM_TRIGGER_VALUE }); //$NON-NLS-1$ - LabelColumnInfo valueCol = new LabelColumnInfo( - new LabelAttribute[] { - new LabelText(new MessageFormat("{0}"), new String[] { PROP_ALARM_TRIGGER_VALUE }) //$NON-NLS-1$ - }); - fLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE, valueCol); - + super(provider, session, AlarmDMContext.class); } @Override protected void updateElementsInSessionThread(final IChildrenUpdate update) { + // Check that the services are available if (!checkService(AlarmService.class, null, update)) return; + if (!checkService(TimerService.class, null, update)) return; - // Retrieve the alarm DMContexts, create the corresponding VMCs array, and - // set them as result. - getServicesTracker().getService(AlarmService.class).getAlarms( - new DataRequestMonitor(getSession().getExecutor(), null) { - @Override - public void handleCompleted() { - if (!getStatus().isOK()) { - update.setStatus(getStatus()); - } else { - fillUpdateWithVMCs(update, getData()); - } - update.done(); - }}); + // Find the trigger and timer contexts. If not found, fail. + TriggerDMContext alarmDmc = findDmcInPath( + update.getViewerInput(), update.getElementPath(), TriggerDMContext.class); + TimerDMContext timerDmc = findDmcInPath( + update.getViewerInput(), update.getElementPath(), TimerDMContext.class); + if (alarmDmc == null || timerDmc == null) { + update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path")); + update.done(); + return; + } + + // Get the alarm context then check the triggered value. + final AlarmDMContext alarmStatusDmc = getServicesTracker().getService(AlarmService.class). + getAlarmS(alarmDmc, timerDmc); + boolean triggered = getServicesTracker().getService(AlarmService.class). + isAlarmTriggered(alarmStatusDmc); + + // Only return the alarm in list of elements if it is triggered. + if (triggered) { + update.setChild(createVMContext(alarmStatusDmc), 0); + } + update.done(); } public void update(ILabelUpdate[] updates) { - fLabelProvider.update(updates); - } - - public void update(final IPropertiesUpdate[] updates) { - try { - getSession().getExecutor().execute(new DsfRunnable() { - public void run() { - for (IPropertiesUpdate update : updates) { - updatePropertiesInSessionThread(update); - } - }}); - } catch (RejectedExecutionException e) { - for (IViewerUpdate update : updates) { - handleFailedUpdate(update); - } + for (ILabelUpdate update : updates) { + update.setLabel("ALARM TRIGGERED", 0); + update.setImageDescriptor( + DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( + DsfExamplesPlugin.IMG_ALARM_TRIGGERED), + 0); + update.done(); } } - - @ConfinedToDsfExecutor("getSession#getExecutor") - protected void updatePropertiesInSessionThread(final IPropertiesUpdate update) { - final AlarmDMC dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), AlarmDMC.class); - if (!checkDmc(dmc, update) || !checkService(AlarmService.class, null, update)) return; - - getDMVMProvider().getModelData( - this, update, - getServicesTracker().getService(AlarmService.class, null), - dmc, - new DataRequestMonitor(getSession().getExecutor(), null) { - @Override - protected void handleCompleted() { - /* - * Check that the request was evaluated and data is still - * valid. The request could fail if the state of the - * service changed during the request, but the view model - * has not been updated yet. - */ - if (!getStatus().isOK() || !getData().isValid()) { - assert getStatus().isOK() || - getStatus().getCode() != IDsfService.INTERNAL_ERROR || - getStatus().getCode() != IDsfService.NOT_SUPPORTED; - handleFailedUpdate(update); - return; - } - - update.setProperty(PROP_ALARM_NUMBER, getData().getAlarmNumber()); - update.setProperty(PROP_ALARM_TRIGGER_VALUE, getData().getTriggeringValue()); - update.done(); - } - }, - getExecutor()); - } - public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) { - if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) { - return new TextCellEditor(parent); - } - return null; - } - - // Note: this method is synchronized because IElementEditor.getCellModifier can be called - // on any thread, even though in practice it should be only called on the UI thread. - public synchronized ICellModifier getCellModifier(IPresentationContext context, Object element) { - if (fAlarmCellModifier == null) { - fAlarmCellModifier = new AlarmCellModifier(getSession()); - } - return fAlarmCellModifier; - } public int getDeltaFlags(Object e) { - // Since the label for alarms doesn't change, this node will generate - // delta info only if the list of alarms is changed. - if (e instanceof AlarmService.AlarmsChangedEvent) { - return IModelDelta.CONTENT; + if (e instanceof AlarmService.AlarmTriggeredEvent) { + return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND; } return IModelDelta.NO_CHANGE; } - - - public void buildDelta(Object event, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) { - if (event instanceof AlarmService.AlarmsChangedEvent) { - // The list of alarms has changed, which means that the parent - // node needs to refresh its contents, which in turn will re-fetch the - // elements from this node. - parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + + public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) { + // The alarm element is added when and selected upon a triggered event. + // Parent element is also expanded allow the alarm to be selected. + if (e instanceof AlarmService.AlarmTriggeredEvent) { + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND); + parentDelta.addNode( + createVMContext( ((AlarmService.AlarmTriggeredEvent)e).getDMContext() ), + 0, + IModelDelta.ADDED | IModelDelta.SELECT); } requestMonitor.done(); - } - - @Override - public synchronized void dispose() { - synchronized(this) { - if (fAlarmCellModifier != null) { - fAlarmCellModifier.dispose(); - } - } - super.dispose(); - } - - public String getPropertyDescription(String property) { - // TODO Auto-generated method stub - return null; - } - - public String getPropertyName(String property) { - // TODO Auto-generated method stub - return null; } } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesShutdownSequence.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesShutdownSequence.java index 8ad1baa9a9c..0df9281a21d 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesShutdownSequence.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesShutdownSequence.java @@ -20,15 +20,19 @@ import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; /** - * Shutdown sequence that stops the services in the timers session. - * + * Sequence that stops the services in the timers session. */ -class ServicesShutdownSequence extends Sequence { +public class ServicesShutdownSequence extends Sequence { - DsfSession fSession; + // Session to that the services are running in. + final private DsfSession fSession; + + // DSF Services is created as the first step of the sequence. It + // cannot be created by the constructor because it can only be called + // in the session thread. DsfServicesTracker fTracker; - ServicesShutdownSequence(DsfSession session) { + public ServicesShutdownSequence(DsfSession session) { super(session.getExecutor()); fSession = session; } @@ -43,6 +47,8 @@ class ServicesShutdownSequence extends Sequence { @Override public void rollBack(RequestMonitor requestMonitor) { + // Dispose the tracker in case shutdown sequence is aborted + // and is rolled back. fTracker.dispose(); fTracker = null; requestMonitor.done(); @@ -63,6 +69,7 @@ class ServicesShutdownSequence extends Sequence { new Step() { @Override public void execute(RequestMonitor requestMonitor) { + // Dispose the tracker after the services are shut down. fTracker.dispose(); fTracker = null; requestMonitor.done(); @@ -73,18 +80,18 @@ class ServicesShutdownSequence extends Sequence { @Override public Step[] getSteps() { return fSteps; } - /** - * Convenience method that shuts down given service. Only service class - * is used to identify the service. - */ + // A convenience method that shuts down given service. Only service class + // is used to identify the service. private void shutdownService(Class clazz, RequestMonitor requestMonitor) { IDsfService service = fTracker.getService(clazz); if (service != null) { service.shutdown(requestMonitor); } else { - requestMonitor.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, - "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + requestMonitor.setStatus(new Status( + IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, + IDsfService.INTERNAL_ERROR, + "Service '" + clazz.getName() + "' not found.", null)); requestMonitor.done(); } } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesStartupSequence.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesStartupSequence.java index 5ac0f2c7252..59b110e3da2 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesStartupSequence.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/ServicesStartupSequence.java @@ -16,16 +16,18 @@ import org.eclipse.dd.dsf.service.DsfSession; /** * Startup sequence for the timers session. With only two services, this is - * a very simple sequence. Last step creates the first timer and alarm. + * a very simple sequence. */ -class ServicesStartupSequence extends Sequence { +public class ServicesStartupSequence extends Sequence { - DsfSession fSession; + final private DsfSession fSession; + + // The reference to the services are saved to use in the last step. private TimerService fTimerService = null; private AlarmService fAlarmService = null; - ServicesStartupSequence(DsfSession session) { + public ServicesStartupSequence(DsfSession session) { super(session.getExecutor()); fSession = session; } @@ -46,8 +48,9 @@ class ServicesStartupSequence extends Sequence { new Step() { @Override public void execute(RequestMonitor requestMonitor) { + // Create the first timer and trigger. fTimerService.startTimer(); - fAlarmService.createAlarm(5); + fAlarmService.createTrigger(5); requestMonitor.done(); }} }; diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimerService.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimerService.java index 154e4ce1a8e..1ab01d63d93 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimerService.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimerService.java @@ -10,21 +10,18 @@ *******************************************************************************/ package org.eclipse.dd.examples.dsf.timers; +import java.util.HashMap; import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.AbstractDMContext; import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; import org.eclipse.dd.dsf.datamodel.IDMContext; -import org.eclipse.dd.dsf.datamodel.IDMData; -import org.eclipse.dd.dsf.datamodel.IDMService; import org.eclipse.dd.dsf.service.AbstractDsfService; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; @@ -32,121 +29,73 @@ import org.osgi.framework.BundleContext; /** * Timer service tracks a set of timers, which are created per user request. - * The timers and their data are provided by the service using the DSF data - * model interfaces. - *

- * When each timer is created, an event is issued that the service contents are - * changed, and clients should re-query the list of timers. The timers - * increment their value at rate of one per second (but they are not synchronous), - * and an event is issued for every tick. + * The timers are represented using a Data Model context object, which + * implements {@link IDMContext}. Each timers value, which can be retrieved + * by calling {@link #getTimerValue(TimerDMContext)}, is incremented every + * second. When a timer value is incremented the TimerService issues a + * {@link TimerTickDMEvent}. */ public class TimerService extends AbstractDsfService - implements IDMService { - /** - * Event indicating that the list of timers is changed and the clients - * which display timers should re-query this list. - */ - public class TimersChangedEvent extends AbstractDMEvent { - TimersChangedEvent() { super(fTimersContext); } - } + /** Event indicating that the list of timers is changed. */ + @Immutable + public static class TimersChangedEvent {} - /** - * Timer context represents a timer in this service. Clients can use this - * context to retrieve timer data. This class implements the Comaparable - * interfaces so that the objects can be stored in a TreeMap, which keeps them sorted. - */ - public static class TimerDMC extends AbstractDMContext - implements Comparable - { - /** - * Timer number, which is also index to timers map. - */ - final int fTimer; + /** Data Model context representing a timer. */ + @Immutable + public static class TimerDMContext extends AbstractDMContext { + final int fNumber; - public TimerDMC(TimerService service, int timer) { - super(service, new IDMContext[] { service.fTimersContext }); - fTimer = timer; + public TimerDMContext(String sessionId, int timer) { + super(sessionId, new IDMContext[0]); + fNumber = timer; } - /** - * Timer context objects are created as needed and not cached, so the - * equals method implementation is critical. - */ + /** Returns the sequential creation number of this timer. */ + public int getTimerNumber() { + return fNumber; + } + + // Timer context objects are created as needed and not cached, so the + // equals method implementation is critical. @Override public boolean equals(Object other) { - return baseEquals(other) && ((TimerDMC)other).fTimer == fTimer; + return baseEquals(other) && + ((TimerDMContext)other).fNumber == fNumber; } @Override - public int hashCode() { return baseHashCode() + fTimer; } + public int hashCode() { return baseHashCode() + fNumber; } @Override public String toString() { - return baseToString() + ".timer[" + fTimer + "]"; //$NON-NLS-1$ //$NON-NLS-2$ - } - - public int compareTo(TimerDMC other) { - TimerDMC otherTimer = other; - return (fTimer < otherTimer.fTimer ? -1 : (fTimer == otherTimer.fTimer ? 0 : 1)); + return baseToString() + ".timer[" + fNumber + "]"; } } - /** - * Data about the timer in the service. This object references internal - * service data, so it has to guard agains this data being obsolete. - */ - public class TimerData implements IDMData { - TimerDMC fTimerDMC; - - TimerData(TimerDMC timer) { fTimerDMC = timer; } - public boolean isValid() { return fTimers.containsKey(fTimerDMC); } - public int getTimerNumber() { return fTimerDMC.fTimer; } - - public int getTimerValue() { - if (!isValid()) return -1; - return fTimers.get(fTimerDMC); - } - - @Override public String toString() { return "Timer " + fTimerDMC.fTimer + " = " + getTimerValue(); } //$NON-NLS-1$ //$NON-NLS-2$ - } - /** * Event indicating that a timer's value has incremented. The context in * the event points to the timer that has changed. */ - public class TimerTickEvent extends AbstractDMEvent { - public TimerTickEvent(TimerDMC context) { + public class TimerTickDMEvent extends AbstractDMEvent { + public TimerTickDMEvent(TimerDMContext context) { super(context); } } - /** Parnet context for all timers */ - private final IDMContext fTimersContext; - /** Counter for generating timer numbers */ - private int fTimerCounter = 1; + private int fTimerNumberCounter = 1; - /** Map holding the timers */ - private Map fTimers = new TreeMap(); + // Use a linked hash in order to be able to return an ordered list of timers. + private Map fTimers = + new LinkedHashMap(); + + private Map> fTimerFutures = + new HashMap>(); - private Map> fTimerFutures = new TreeMap>(); - /** Constructor requires only the session for this service */ TimerService(DsfSession session) { super(session); - fTimersContext = new AbstractDMContext(this, new IDMContext[0]) { - private final Object fHashObject = new Object(); - - @Override - public boolean equals(Object obj) { return (this == obj); }; - - @Override - public int hashCode() { return fHashObject.hashCode(); } - - @Override - public String toString() { return "#timers"; } //$NON-NLS-1$ - }; } @Override @@ -160,97 +109,72 @@ public class TimerService extends AbstractDsfService new RequestMonitor(getExecutor(), requestMonitor) { @Override public void handleOK() { + // After super-class is finished initializing + // perform TimerService initialization. doInitialize(requestMonitor); }}); } + private void doInitialize(RequestMonitor requestMonitor) { + // Register service + register( new String[]{ TimerService.class.getName() }, + new Hashtable() ); + requestMonitor.done(); + } + @Override public void shutdown(RequestMonitor requestMonitor) { - /* - * Go through all the timer futures and cancel them, so that they - * don't fire any more events. - */ + // Cancel timer futures to avoid firing more events. for (Future future : fTimerFutures.values()) { future.cancel(false); } unregister(); super.shutdown(requestMonitor); } - - /** - * Performs the relevant initialization for this service: registering and - * scheduling the timer. - * @param requestMonitor - */ - private void doInitialize(RequestMonitor requestMonitor) { - register(new String[]{TimerService.class.getName()}, new Hashtable()); - requestMonitor.done(); + + /** Retrieves the list of timer contexts. */ + public TimerDMContext[] getTimers() { + return fTimers.keySet().toArray(new TimerDMContext[fTimers.size()]); } - public boolean isValid() { return true; } - - @SuppressWarnings("unchecked") - public void getModelData(IDMContext dmc, DataRequestMonitor rm) { - if (dmc instanceof TimerDMC) { - getTimerData((TimerDMC)dmc, (DataRequestMonitor)rm); - return; - } else if (dmc == fTimersContext) { - ((DataRequestMonitor)rm).setData(this); - } else { - rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ - } - rm.done(); + /** Retrieves the timer value for the given context. */ + public int getTimerValue(TimerDMContext context) { + Integer value = fTimers.get(context); + if (value != null) { + return value; + } + return -1; } - /** - * Retrieves the list of timer contexts. - * - *
Note: this method doesn't need to be asynchronous, because all the - * data is stored locally. But using an asynchronous method makes this a - * more applicable example. - * - * @param rm Return data token. - */ - public void getTimers(DataRequestMonitor rm) { - rm.setData( fTimers.keySet().toArray(new TimerDMC[fTimers.size()]) ); - rm.done(); - } - - /** - * Retrieves the data object for given timer context. - * - *
Note: likewise this method doesn't need to be asynchronous. - */ - public void getTimerData(TimerDMC context, DataRequestMonitor rm) { - rm.setData(new TimerData(context)); - rm.done(); - } - - /** - * Creates a new timer and returns its context. - */ - public TimerDMC startTimer() { - final TimerDMC newTimer = new TimerDMC(this, fTimerCounter++); + /** Creates a new timer and returns its context. */ + public TimerDMContext startTimer() { + // Create a new timer context and add it to the internal list. + final TimerDMContext newTimer = + new TimerDMContext(getSession().getId(), fTimerNumberCounter++); fTimers.put(newTimer, 0); + + // Create a new runnable that will execute every second and increment + // the timer value. The returned future is the handle that allows + // for canceling the scheduling of the runnable. Future timerFuture = getExecutor().scheduleAtFixedRate( new Runnable() { public void run() { fTimers.put(newTimer, fTimers.get(newTimer) + 1); - getSession().dispatchEvent(new TimerTickEvent(newTimer), getProperties()); + getSession().dispatchEvent(new TimerTickDMEvent(newTimer), getProperties()); } @Override public String toString() { return "Scheduled timer runnable for timer " + newTimer; } //$NON-NLS-1$ }, 1, 1, TimeUnit.SECONDS); - fTimerFutures.put(newTimer, timerFuture); + fTimerFutures.put(newTimer, timerFuture); + + // Issue an event to allow clients to update the list of timers. getSession().dispatchEvent(new TimersChangedEvent(), getProperties()); return newTimer; } - /** - * Removes given timer from list of timers. - */ - public void killTimer(TimerDMC timerContext) { + /** Removes given timer from list of timers. */ + public void killTimer(TimerDMContext timerContext) { if (fTimers.containsKey(timerContext)) { fTimers.remove(timerContext); fTimerFutures.remove(timerContext).cancel(false); diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersRootVMNode.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersRootVMNode.java new file mode 100644 index 00000000000..bc59bf0ae24 --- /dev/null +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersRootVMNode.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.examples.dsf.timers; + +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.RootDMVMNode; +import org.eclipse.dd.examples.dsf.timers.TimersVMProvider.TimersViewLayoutChanged; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; + +/** + * + */ +@SuppressWarnings("restriction") +public class TimersRootVMNode extends RootDMVMNode { + + public TimersRootVMNode(AbstractVMProvider provider) { + super(provider); + } + + @Override + public boolean isDeltaEvent(Object rootObject, Object e) { + if (e instanceof TimersViewLayoutChanged) { + return true; + } + return super.isDeltaEvent(rootObject, e); + } + + @Override + public int getDeltaFlags(Object e) { + if (e instanceof TimersViewLayoutChanged) { + return IModelDelta.CONTENT; + } + + return IModelDelta.NO_CHANGE; + } + + @Override + public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor rm) { + rm.setData(new VMDelta(rootObject, 0, IModelDelta.NO_CHANGE)); + int flags = IModelDelta.NO_CHANGE; + if (event instanceof TimersViewLayoutChanged) { + flags |= IModelDelta.CONTENT; + } + rm.setData( new VMDelta(rootObject, 0, flags) ); + rm.done(); + } + +} diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersModelAdapter.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMAdapter.java similarity index 50% rename from plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersModelAdapter.java rename to plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMAdapter.java index bd694680da7..8010674b540 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersModelAdapter.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMAdapter.java @@ -14,49 +14,28 @@ import org.eclipse.dd.dsf.concurrent.ThreadSafe; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter; -import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; /** * This is the adapter that implements the flexible hierarchy viewer interfaces - * for providing content, labels, and event proxy-ing for the viewer. This + * for providing content, labels, and event processing for the viewer. This * adapter is registered with the DSF Session object, and is returned by the * IDMContext.getAdapter() and IVMContext.getAdapter() methods, * which both call {@link DsfSession#getModelAdapter(Class)}. - *

- * The adapter implementation for this excercise is hard-coded to provide - * contents for only one view. In turn the view contens are determined using - * the configurable ViewModelProvider. For demonstration purposes, this model - * adapter has two different layout configurations that can be used. These - * layout configurations can be set by calling the {@link #setViewLayout} method. - *

- * This class is primarily accessed by the flexible hierarchy viewer from a - * non-executor thread. So the class is thread-safe, except for a view methods - * which must be called on the executor thread. - * - * @see AbstractDMVMProvider */ @SuppressWarnings("restriction") @ThreadSafe -public class TimersModelAdapter extends AbstractDMVMAdapter +public class TimersVMAdapter extends AbstractDMVMAdapter { - TimersVMProvider fViewModelProvider; - @Override protected IVMProvider createViewModelProvider(IPresentationContext context) { - /* - * In this example there is only one viewer, so there is only one - * VMProvider. - */ - return fViewModelProvider; + if ( TimersView.ID_VIEW_TIMERS.equals(context.getId()) ) { + return new TimersVMProvider(this, context, getSession()); + } + return null; } - public TimersModelAdapter(DsfSession session, IPresentationContext presentationContext) { + public TimersVMAdapter(DsfSession session, IPresentationContext presentationContext) { super(session); - fViewModelProvider = new TimersVMProvider(this, presentationContext, getSession()); } - - TimersVMProvider getTimersVMProvider() { - return fViewModelProvider; - } } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMNode.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMNode.java index 52fd1a7f444..64c0186a12f 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMNode.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMNode.java @@ -10,38 +10,76 @@ *******************************************************************************/ package org.eclipse.dd.examples.dsf.timers; +import java.text.MessageFormat; import java.util.concurrent.RejectedExecutionException; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.dd.dsf.concurrent.DsfRunnable; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.service.DsfSession; -import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider; +import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText; +import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerData; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; /** * View model node that defines how timer DMContexts are displayed in the view. Timers * change with every tick of the timer, so the label has to be repained * upon timer tick events. - * @see TimerDMC + * @see TimerDMContext */ @SuppressWarnings("restriction") class TimersVMNode extends AbstractDMVMNode - implements IElementLabelProvider + implements IElementLabelProvider, IElementPropertiesProvider { + private static final String PROP_TIMER_NUMBER = "alarmNumber"; + private static final String PROP_TIMER_VALUE = "alarmTriggerValue"; + + // Create and configure the label provider. + private static final PropertyBasedLabelProvider fgLabelProvider; + static { + fgLabelProvider = new PropertyBasedLabelProvider(); + + LabelColumnInfo idCol = new LabelColumnInfo( + new LabelAttribute[] { + new LabelText(new MessageFormat("Timer #{0}"), + new String[] { PROP_TIMER_NUMBER }), + new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry(). + getDescriptor(DsfExamplesPlugin.IMG_ALARM)) + }); + fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol); + + LabelColumnInfo valueCol = new LabelColumnInfo( + new LabelAttribute[] { + new LabelText(new MessageFormat("{0}"), + new String[] { PROP_TIMER_VALUE }) + }); + fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE, + valueCol); + + } + public TimersVMNode(AbstractDMVMProvider provider, DsfSession session) { - super(provider, session, TimerDMC.class); + super(provider, session, TimerDMContext.class); + } + + public void update(ILabelUpdate[] updates) { + fgLabelProvider.update(updates); } @Override @@ -50,93 +88,60 @@ class TimersVMNode extends AbstractDMVMNode // Retrieve the timer DMContexts, create the corresponding VMCs array, and // set them as result. - getServicesTracker().getService(TimerService.class).getTimers( - new DataRequestMonitor(getSession().getExecutor(), null) { - @Override - public void handleCompleted() { - if (!getStatus().isOK()) { - update.setStatus(getStatus()); - } else { - fillUpdateWithVMCs(update, getData()); - } - update.done(); - }}); + TimerDMContext[] timers = + getServicesTracker().getService(TimerService.class).getTimers(); + fillUpdateWithVMCs(update, timers); + update.done(); } - public void update(final ILabelUpdate[] updates) { + public void update(final IPropertiesUpdate[] updates) { + // Switch to the session thread before processing the updates. try { getSession().getExecutor().execute(new DsfRunnable() { public void run() { - updateLabelInSessionThread(updates); + for (IPropertiesUpdate update : updates) { + updatePropertiesInSessionThread(update); + } }}); } catch (RejectedExecutionException e) { - for (ILabelUpdate update : updates) { + for (IViewerUpdate update : updates) { handleFailedUpdate(update); } } } - - protected void updateLabelInSessionThread(ILabelUpdate[] updates) { - for (final ILabelUpdate update : updates) { - final TimerDMC dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMC.class); - if (!checkDmc(dmc, update) || !checkService(TimerService.class, null, update)) continue; - - getDMVMProvider().getModelData( - this, update, - getServicesTracker().getService(TimerService.class, null), - dmc, - new DataRequestMonitor(getSession().getExecutor(), null) { - @Override - protected void handleCompleted() { - /* - * Check that the request was evaluated and data is still - * valid. The request could fail if the state of the - * service changed during the request, but the view model - * has not been updated yet. - */ - if (!getStatus().isOK() || !getData().isValid()) { - assert getStatus().isOK() || - getStatus().getCode() != IDsfService.INTERNAL_ERROR || - getStatus().getCode() != IDsfService.NOT_SUPPORTED; - handleFailedUpdate(update); - return; - } - - /* - * If columns are configured, call the protected methods to - * fill in column values. - */ - String[] localColumns = update.getPresentationContext().getColumns(); - if (localColumns == null) localColumns = new String[] { null }; - - for (int i = 0; i < localColumns.length; i++) { - fillColumnLabel(dmc, getData(), localColumns[i], i, update); - } - update.done(); - } - }, - getExecutor()); + @ConfinedToDsfExecutor("getSession#getExecutor") + private void updatePropertiesInSessionThread(final IPropertiesUpdate update) { + // Find the timer context in the element being updated + final TimerDMContext dmc = findDmcInPath( + update.getViewerInput(), update.getElementPath(), TimerDMContext.class); + + // If either update or service are not valid, fail the update and exit. + if (!checkDmc(dmc, update) || + !checkService(TimerService.class, null, update)) + { + return; } + + TimerService timerService = + getServicesTracker().getService(TimerService.class, null); + int value = timerService.getTimerValue(dmc); + + if (value == -1) { + handleFailedUpdate(update); + return; + } + + update.setProperty(PROP_TIMER_NUMBER, dmc.getTimerNumber()); + update.setProperty(PROP_TIMER_VALUE, value); + update.done(); } - protected void fillColumnLabel(TimerDMC dmContext, TimerData dmData, String columnId, int idx, - ILabelUpdate update) - { - if (TimersViewColumnPresentation.COL_ID.equals(columnId)) { - update.setLabel( Integer.toString(dmData.getTimerNumber()), idx ); - update.setImageDescriptor( - DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(DsfExamplesPlugin.IMG_TIMER), idx); - } else if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) { - update.setLabel( Integer.toString(dmData.getTimerValue()), idx); - } - } - public int getDeltaFlags(Object e) { // This node generates delta if the timers have changed, or if the // label has changed. - if (e instanceof TimerService.TimerTickEvent) { + if (e instanceof TimerService.TimerTickDMEvent) { return IModelDelta.STATE; } else if (e instanceof TimerService.TimersChangedEvent) { return IModelDelta.CONTENT; @@ -145,10 +150,9 @@ class TimersVMNode extends AbstractDMVMNode } public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) { - if (e instanceof TimerService.TimerTickEvent) { - // Add delta indicating that the VMC for the given timer context - // has changed. - parentDelta.addNode( createVMContext(((TimerService.TimerTickEvent)e).getDMContext()), IModelDelta.STATE ); + if (e instanceof TimerService.TimerTickDMEvent) { + // Add delta indicating that the given timer has changed. + parentDelta.addNode( createVMContext(((TimerService.TimerTickDMEvent)e).getDMContext()), IModelDelta.STATE ); } else if (e instanceof TimerService.TimersChangedEvent) { // The list of timers has changed, which means that the parent // node needs to refresh its contents, which in turn will re-fetch the @@ -157,4 +161,14 @@ class TimersVMNode extends AbstractDMVMNode } requestMonitor.done(); } + + + public String getPropertyDescription(String property) { + return null; + } + + public String getPropertyName(String property) { + return null; + } + } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMProvider.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMProvider.java index 92f55d00aec..a19d6e31528 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMProvider.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersVMProvider.java @@ -10,60 +10,42 @@ *******************************************************************************/ package org.eclipse.dd.examples.dsf.timers; -import org.eclipse.core.runtime.IAdaptable; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.RootVMNode; -import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMModelProxyStrategy; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggersChangedEvent; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimersChangedEvent; import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; /** - * + * The View Model provider for the Timers view. This provider allows for + * switching between two different view layouts: + *

    + *
  1. Timers -> Triggers -> Alarms
  2. + *
  3. Triggers -> Timers -> Alarms
  4. + *
+ * A special event is sent when the layout is changed in order to generate + * a proper delta to refresh the view. */ @SuppressWarnings("restriction") public class TimersVMProvider extends AbstractDMVMProvider { - /** - * The object to be set to the viewer that shows contents supplied by this provider. - * @see org.eclipse.jface.viewers.TreeViewer#setInput(Object) - */ - private final IAdaptable fViewerInputObject = - new IAdaptable() { - /** - * The input object provides the viewer access to the viewer model adapter. - */ - @SuppressWarnings("unchecked") - public Object getAdapter(Class adapter) { - if ( adapter.isInstance(getVMAdapter()) ) { - return getVMAdapter(); - } - return null; - } - - @Override - public String toString() { - return "Timers View Root"; //$NON-NLS-1$ - } - }; - - private DefaultVMModelProxyStrategy fModelProxyStrategy; - - + /** Event indicating that the timers view layout has changed */ + public static class TimersViewLayoutChanged {} + /** Enumeration of possible layouts for the timers view model */ - public enum ViewLayout { ALARMS_AT_TOP, TIMERS_AT_TOP } + public enum ViewLayout { TRIGGERS_AT_TOP, TIMERS_AT_TOP } public TimersVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) { super(adapter, presentationContext, session); - setViewLayout(ViewLayout.ALARMS_AT_TOP); - } - - - public Object getViewerInputObject() { - return fViewerInputObject; + // Set the initial view layout. + setViewLayout(ViewLayout.TIMERS_AT_TOP); } /** @@ -71,33 +53,30 @@ public class TimersVMProvider extends AbstractDMVMProvider { * @param layout New layout to use. */ public void setViewLayout(ViewLayout layout) { - if (layout == ViewLayout.ALARMS_AT_TOP) { - IRootVMNode root = new RootVMNode(this); - IVMNode alarmsNode = new AlarmsVMNode(this, getSession()); - IVMNode timersNode0 = new TimersVMNode(this, getSession()); - addChildNodes(root, new IVMNode[] { alarmsNode, timersNode0 }); + clearNodes(); + if (layout == ViewLayout.TRIGGERS_AT_TOP) { + IRootVMNode root = new TimersRootVMNode(this); + IVMNode alarmsNode = new TriggersVMNode(this, getSession()); + addChildNodes(root, new IVMNode[] { alarmsNode }); IVMNode timersNode = new TimersVMNode(this, getSession()); addChildNodes(alarmsNode, new IVMNode[] { timersNode }); - IVMNode alarmStatusNode = new AlarmStatusVMNode(this, getSession()); + IVMNode alarmStatusNode = new AlarmsVMNode(this, getSession()); addChildNodes(timersNode, new IVMNode[] { alarmStatusNode }); setRootNode(root); } else if (layout == ViewLayout.TIMERS_AT_TOP) { - IRootVMNode root = new RootVMNode(this); + IRootVMNode root = new TimersRootVMNode(this); IVMNode timersNode = new TimersVMNode(this, getSession()); addChildNodes(root, new IVMNode[] { timersNode }); - IVMNode alarmsNode = new AlarmsVMNode(this, getSession()); + IVMNode alarmsNode = new TriggersVMNode(this, getSession()); addChildNodes(timersNode, new IVMNode[] { alarmsNode }); - IVMNode alarmStatusNode = new AlarmStatusVMNode(this, getSession()); + IVMNode alarmStatusNode = new AlarmsVMNode(this, getSession()); addChildNodes(alarmsNode, new IVMNode[] { alarmStatusNode }); setRootNode(root); } - /* TODO: replace with an event - fModelProxyStrategy.fireModelChanged( - new ModelDelta(getRootElement(), IModelDelta.CONTENT)); - */ + handleEvent(new TimersViewLayoutChanged()); } - + @Override public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) { return new TimersViewColumnPresentation(); @@ -107,5 +86,36 @@ public class TimersVMProvider extends AbstractDMVMProvider { public String getColumnPresentationId(IPresentationContext context, Object element) { return TimersViewColumnPresentation.ID; } - + + // Add a handler for the triggers and timers changed events. The + // AbstractDMVMProvider superclass automatically registers this provider + // for all IDMEvent events, however these two events do not implement + // IDMEvent + @DsfServiceEventHandler + public void eventDispatched(final TriggersChangedEvent event) { + if (isDisposed()) return; + + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + handleEvent(event); + } + }); + } catch (RejectedExecutionException e) {} + } + + @DsfServiceEventHandler + public void eventDispatched(final TimersChangedEvent event) { + if (isDisposed()) return; + + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + handleEvent(event); + } + }); + } catch (RejectedExecutionException e) {} + } } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersView.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersView.java index f9b4afe2be7..27b96b3ddf3 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersView.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersView.java @@ -12,19 +12,20 @@ package org.eclipse.dd.examples.dsf.timers; import java.util.concurrent.ExecutionException; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor; import org.eclipse.dd.dsf.concurrent.DsfExecutor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.service.DsfServicesTracker; import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC; +import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext; import org.eclipse.dd.examples.dsf.timers.TimersVMProvider.ViewLayout; import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; -import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; import org.eclipse.jface.action.Action; @@ -33,6 +34,7 @@ import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; @@ -42,17 +44,23 @@ import org.eclipse.ui.part.ViewPart; /** - * Example view which displays data from timers and alarms DSF services. This - * starts a new DSF session and configures the services for it. Then it - * configures a data model provider to process the service data and display it - * in a flexible-hierarchy asynchronous viewer. + * Example view which displays data from timers and alarms services. It starts + * a new DSF session and configures the services for it. Then it configures + * a data model provider to process the service data and display it in a + * flexible-hierarchy asynchronous viewer. */ @SuppressWarnings("restriction") public class TimersView extends ViewPart { + /** Timers view ID */ + public static final String ID_VIEW_TIMERS = "org.eclipse.dd.examples.dsf.TimersView"; + /** Asynchronous tree viewer from the platform debug.ui plugin. */ private TreeModelViewer fViewer; + /** Presentation context of the timers viewer */ + private PresentationContext fPresentationContext; + /** DSF executor to use for a new session with timers and alarms services */ private DsfExecutor fExecutor; @@ -63,7 +71,7 @@ public class TimersView extends ViewPart { private DsfServicesTracker fServices; /** Adapter used to provide view model for flexible-hierarchy viewer */ - private TimersModelAdapter fTimersModelAdapter; + private TimersVMAdapter fTimersVMAdapter; /** Action which toggles the layout in the viewer */ private Action fToggleLayoutAction; @@ -71,45 +79,41 @@ public class TimersView extends ViewPart { /** Action that adds a new timer */ private Action fAddTimerAction; - /** Action that adds a new alarm */ - private Action fAddAlarmAction; + /** Action that adds a new trigger */ + private Action fAddTriggerAction; - /** Action that removes the selected alarm or timer */ + /** Action that removes the selected trigger or timer */ private Action fRemoveAction; public TimersView() {} /** - * This is a callback that will allow us to create the viewer and + * This is a call-back that will allow us to create the viewer and * initialize it. For this view, it creates the DSF session, along * with its services. Then it creates the viewer model adapter and * registers it with the session. */ @Override public void createPartControl(Composite parent) { - /* - * Create the Flexible Hierarchy viewer. Also create a presentation - * context which will be given to the content/label provider adapters - * to distinguish this view from other flex-hierarchy views. - */ - final IPresentationContext presentationContext = new PresentationContext("org.eclipse.dd.examples.dsf.timers"); //$NON-NLS-1$ - fViewer = new TreeModelViewer(parent, SWT.VIRTUAL | SWT.FULL_SELECTION, presentationContext); + // Create the Flexible Hierarchy viewer. Also create a presentation + // context which will be given to the content/label provider adapters + // to distinguish this view from other flexible-hierarchy views. + fPresentationContext = new PresentationContext(ID_VIEW_TIMERS); + fViewer = new TreeModelViewer( + parent, SWT.VIRTUAL | SWT.FULL_SELECTION, fPresentationContext); - /* - * Create the executor, which will be used exclusively with this view, - * as well as a session and a services tracker for managing references - * to services. - */ + // Create the executor, which will be used exclusively with this view, + // as well as a session and a services tracker for managing references + // to services. fExecutor = new DefaultDsfExecutor(); - fSession = DsfSession.startSession(fExecutor, "org.eclipse.dd.examples.dsf.timers"); //$NON-NLS-1$ - fServices = new DsfServicesTracker(DsfExamplesPlugin.getBundleContext(), fSession.getId()); + fSession = DsfSession.startSession(fExecutor, "Timers(DSF Example)"); + fServices = new DsfServicesTracker( + DsfExamplesPlugin.getBundleContext(), fSession.getId()); - /* - * Start the services using a sequence. The sequence runs in the - * dispatch thread, so we have to block this thread using Future.get() - * until it completes. The Future.get() will throw an exception if - * the sequence fails. - */ + // Start the services using a sequence. The sequence runs in the + // session executor thread, therefore the thread calling this method + // has to block using Future.get() until the sequence it completes. + // The Future.get() will throw an exception if the sequence fails. ServicesStartupSequence startupSeq = new ServicesStartupSequence(fSession); fSession.getExecutor().execute(startupSeq); try { @@ -118,20 +122,38 @@ public class TimersView extends ViewPart { } catch (ExecutionException e) { assert false; } - /* - * Create the flexible hierarchy content/label adapter. Then register - * it with the session. - */ - fTimersModelAdapter = new TimersModelAdapter(fSession, presentationContext); - fSession.registerModelAdapter(IElementContentProvider.class, fTimersModelAdapter); - fSession.registerModelAdapter(IModelProxyFactory.class, fTimersModelAdapter); - fSession.registerModelAdapter(IColumnPresentationFactory.class, fTimersModelAdapter); + // Create the flexible hierarchy content/label adapter. Then register + // it with the session. + fTimersVMAdapter = new TimersVMAdapter(fSession, fPresentationContext); + fSession.registerModelAdapter( + IElementContentProvider.class, fTimersVMAdapter); + fSession.registerModelAdapter( + IModelProxyFactory.class, fTimersVMAdapter); + fSession.registerModelAdapter( + IColumnPresentationFactory.class, fTimersVMAdapter); - /* - * Set the root element for the timers tree viewer. The root element - * comes from the content provider. - */ - fViewer.setInput(fTimersModelAdapter.getTimersVMProvider().getViewerInputObject()); + // Create the input object for the view. This object needs to return + // the VM adapter through the IAdaptable interface when queried for the + // flexible hierarchy adapters. + final IAdaptable viewerInputObject = + new IAdaptable() { + /** + * The input object provides the viewer access to the viewer model adapter. + */ + @SuppressWarnings("unchecked") + public Object getAdapter(Class adapter) { + if ( adapter.isInstance(fTimersVMAdapter) ) { + return fTimersVMAdapter; + } + return null; + } + + @Override + public String toString() { + return "Timers View Root"; //$NON-NLS-1$ + } + }; + fViewer.setInput(viewerInputObject); makeActions(); contributeToActionBars(); @@ -140,21 +162,24 @@ public class TimersView extends ViewPart { @Override public void dispose() { try { - /* - * First dispose the view model, which is the client of services. - * We are not in the dispatch thread - */ + // First dispose the view model, which is the client of services. + // This operation needs to be performed in the session executor + // thread. Block using Future.get() until this call completes. fSession.getExecutor().submit(new Runnable() { public void run() { fSession.unregisterModelAdapter(IElementContentProvider.class); fSession.unregisterModelAdapter(IModelProxyFactory.class); fSession.unregisterModelAdapter(IColumnPresentationFactory.class); - fTimersModelAdapter.dispose(); - fTimersModelAdapter = null; }}).get(); - - // Then invoke the shutdown sequence for the services. - ServicesShutdownSequence shutdownSeq = new ServicesShutdownSequence(fSession); + + // Dispose the VM adapter. + fTimersVMAdapter.dispose(); + fTimersVMAdapter = null; + + // Next invoke the shutdown sequence for the services. Sequence + // class also implements Future.get()... + ServicesShutdownSequence shutdownSeq = + new ServicesShutdownSequence(fSession); fSession.getExecutor().execute(shutdownSeq); try { shutdownSeq.get(); @@ -162,7 +187,7 @@ public class TimersView extends ViewPart { } catch (ExecutionException e) { assert false; } - // Finally end the session and the executor: + // Finally end the session and the executor. fSession.getExecutor().submit(new Runnable() { public void run() { DsfSession.endSession(fSession); @@ -173,7 +198,6 @@ public class TimersView extends ViewPart { } catch (InterruptedException e) { } catch (ExecutionException e) { } - //fViewer.dispose(); super.dispose(); } @@ -185,7 +209,7 @@ public class TimersView extends ViewPart { private void fillLocalToolBar(IToolBarManager manager) { manager.add(fToggleLayoutAction); manager.add(fAddTimerAction); - manager.add(fAddAlarmAction); + manager.add(fAddTriggerAction); manager.add(fRemoveAction); manager.add(new Separator()); } @@ -195,97 +219,105 @@ public class TimersView extends ViewPart { @Override public void run() { // Get the toggle state of the action while on UI thread. - final ViewLayout layout = isChecked() ? ViewLayout.ALARMS_AT_TOP : ViewLayout.TIMERS_AT_TOP; + final ViewLayout layout = isChecked() ? ViewLayout.TRIGGERS_AT_TOP : ViewLayout.TIMERS_AT_TOP; - // Switch to executor thread to perform the change in layout. - fExecutor.submit(new Runnable() { public void run() { - fTimersModelAdapter.getTimersVMProvider().setViewLayout(layout); - }}); + IVMProvider provider = fTimersVMAdapter.getVMProvider(fPresentationContext); + ((TimersVMProvider)provider).setViewLayout(layout); } }; fToggleLayoutAction.setToolTipText("Toggle Layout"); //$NON-NLS-1$ fToggleLayoutAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( DsfExamplesPlugin.IMG_LAYOUT_TOGGLE)); - fAddTimerAction = new Action("Add New Timer") { //$NON-NLS-1$ + fAddTimerAction = new Action("Add New Timer") { @Override public void run() { - fExecutor.submit(new Runnable() { public void run() { - // Only need to create the new timer, the events will cause - // the view to refresh. - fServices.getService(TimerService.class).startTimer(); - }}); + fExecutor.execute(new Runnable() { + public void run() { + // Only need to create the new timer, the events will + // cause the view to refresh. + fServices.getService(TimerService.class).startTimer(); + } + }); } }; - fAddTimerAction.setToolTipText("Add new timer"); //$NON-NLS-1$ - fAddTimerAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( - DsfExamplesPlugin.IMG_TIMER)); + fAddTimerAction.setToolTipText("Add a new timer"); + fAddTimerAction.setImageDescriptor( + getImage(DsfExamplesPlugin.IMG_TIMER)); - fAddAlarmAction = new Action("Add New Alarm") { //$NON-NLS-1$ + fAddTriggerAction = new Action("Add New Trigger") { @Override public void run() { - // Ask user for the new alarm value. + // Ask user for the new trigger value. InputDialog inputDialog = new InputDialog( - fViewer.getControl().getShell(), - "New Alarm", //$NON-NLS-1$ - "Please enter alarm time", //$NON-NLS-1$ - "", //$NON-NLS-1$ + getSite().getShell(), + "New Trigger", + "Please enter trigger value", + "", new IInputValidator() { public String isValid(String input) { try { int i= Integer.parseInt(input); if (i <= 0) - return "Please enter a positive integer"; //$NON-NLS-1$ + return "Please enter a positive integer"; } catch (NumberFormatException x) { - return "Please enter a positive integer"; //$NON-NLS-1$ + return "Please enter a positive integer"; } return null; } } ); if (inputDialog.open() != Window.OK) return; - int tmpAlarmValue = -1; + int tmpTriggerValue = -1; try { - tmpAlarmValue = Integer.parseInt(inputDialog.getValue()); + tmpTriggerValue = Integer.parseInt(inputDialog.getValue()); } catch (NumberFormatException x) { assert false; } - final int alarmValue = tmpAlarmValue; - fExecutor.submit(new Runnable() { public void run() { - // Create the new alarm. - fServices.getService(AlarmService.class).createAlarm(alarmValue); - }}); + final int triggerValue = tmpTriggerValue; + fExecutor.execute(new Runnable() { + public void run() { + // Create the new trigger + fServices.getService(AlarmService.class). + createTrigger(triggerValue); + } + }); } }; - fAddAlarmAction.setToolTipText("Add new alarm"); //$NON-NLS-1$ - fAddAlarmAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( - DsfExamplesPlugin.IMG_ALARM)); + fAddTriggerAction.setToolTipText("Add a new trigger"); + fAddTriggerAction.setImageDescriptor( + getImage(DsfExamplesPlugin.IMG_ALARM)); - fRemoveAction = new Action("Remove") { //$NON-NLS-1$ + fRemoveAction = new Action("Remove") { @Override public void run() { - final Object selectedElement = ((IStructuredSelection)fViewer.getSelection()).getFirstElement(); + final Object selectedElement = + ((IStructuredSelection)fViewer.getSelection()).getFirstElement(); if (!(selectedElement instanceof IDMVMContext)) return; - final IDMContext selectedDmc = ((IDMVMContext)selectedElement).getDMContext(); - // Based on the DMC from the selection, call the appropriate service to - // remove the item. - if (selectedDmc instanceof TimerDMC) { - fExecutor.submit(new Runnable() { public void run() { + final IDMContext selectedCtx = + ((IDMVMContext)selectedElement).getDMContext(); + // Based on the context from the selection, call the + // appropriate service to remove the item. + if (selectedCtx instanceof TimerDMContext) { + fExecutor.execute(new Runnable() { public void run() { fServices.getService(TimerService.class).killTimer( - ((TimerDMC)selectedDmc)); + ((TimerDMContext)selectedCtx)); }}); - } else if (selectedDmc instanceof AlarmService.AlarmDMC) { - fExecutor.submit(new Runnable() { public void run() { - fServices.getService(AlarmService.class).deleteAlarm( - (AlarmService.AlarmDMC)selectedDmc); + } else if (selectedCtx instanceof AlarmService.TriggerDMContext) { + fExecutor.execute(new Runnable() { public void run() { + fServices.getService(AlarmService.class).deleteTrigger( + (AlarmService.TriggerDMContext)selectedCtx); }}); } } }; - fRemoveAction.setToolTipText("Remove selected item"); //$NON-NLS-1$ - fRemoveAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor( - DsfExamplesPlugin.IMG_REMOVE)); + fRemoveAction.setToolTipText("Remove selected item"); + fRemoveAction.setImageDescriptor( getImage(DsfExamplesPlugin.IMG_REMOVE) ); } + private ImageDescriptor getImage(String key) { + return DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(key); + } + /** * Passing the focus request to the viewer's control. */ diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersViewColumnPresentation.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersViewColumnPresentation.java index ba24f6b68dc..fb3052863ae 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersViewColumnPresentation.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TimersViewColumnPresentation.java @@ -25,18 +25,14 @@ public class TimersViewColumnPresentation implements IColumnPresentation { public static final String COL_ID = ID + ".COL_ID"; //$NON-NLS-1$ public static final String COL_VALUE = ID + ".COL_VALUE"; //$NON-NLS-1$ - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#init(org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext) public void init(IPresentationContext context) {} - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#dispose() public void dispose() {} - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getAvailableColumns() public String[] getAvailableColumns() { return new String[] { COL_ID, COL_VALUE }; } - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getHeader(java.lang.String) public String getHeader(String id) { if (COL_ID.equals(id)) { return "ID"; //$NON-NLS-1$ @@ -46,22 +42,18 @@ public class TimersViewColumnPresentation implements IColumnPresentation { return null; } - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getId() public String getId() { return ID; } - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getImageDescriptor(java.lang.String) public ImageDescriptor getImageDescriptor(String id) { return null; } - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getInitialColumns() public String[] getInitialColumns() { return getAvailableColumns(); } - // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#isOptional() public boolean isOptional() { return true; } diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmCellModifier.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggerCellModifier.java similarity index 65% rename from plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmCellModifier.java rename to plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggerCellModifier.java index e0ae7d54606..8b02fb5b788 100644 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/AlarmCellModifier.java +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggerCellModifier.java @@ -11,6 +11,7 @@ package org.eclipse.dd.examples.dsf.timers; import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; @@ -23,8 +24,7 @@ import org.eclipse.dd.dsf.service.DsfServices; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC; -import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmData; +import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.swt.widgets.Shell; @@ -32,58 +32,56 @@ import org.osgi.framework.InvalidSyntaxException; import org.osgi.util.tracker.ServiceTracker; /** - * + * Cell modifier used to edit the trigger value. */ -@ThreadSafeAndProhibitedFromDsfExecutor("") -public class AlarmCellModifier implements ICellModifier { +@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()") +public class TriggerCellModifier implements ICellModifier { private final DsfSession fSession; - /** - * Need to use the OSGi service tracker here (instead of DsfServiceTracker), - * because we're accessing it in non-dispatch thread. DsfServiceTracker is not - * thread-safe. - */ + // Need to use the OSGi service tracker (instead of DsfServiceTracker), + // because it's being accessed on multiple threads. @ThreadSafe private ServiceTracker fServiceTracker; /** - * Constructor for the modifier requires a valid DSF session in order to + * Constructor for the modifier requires a valid session in order to * initialize the service tracker. * @param session DSF session this modifier will use. */ - public AlarmCellModifier(DsfSession session) { + public TriggerCellModifier(DsfSession session) { fSession = session; } public boolean canModify(Object element, String property) { - return TimersViewColumnPresentation.COL_VALUE.equals(property) && getAlarmDMC(element) != null; + return TimersViewColumnPresentation.COL_VALUE.equals(property) && + getAlarmDMC(element) != null; } public Object getValue(Object element, String property) { - if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return ""; //$NON-NLS-1$ + if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return ""; - // Get the DMC and the session. If element is not an alarm DMC, or - // session is stale, then bail out. - AlarmDMC dmc = getAlarmDMC(element); - if (dmc == null) return ""; //$NON-NLS-1$ - DsfSession session = DsfSession.getSession(dmc.getSessionId()); - if (session == null) return ""; //$NON-NLS-1$ + // Get the context and the session. If element is not an trigger + // context or if the session is stale then bail out. + TriggerDMContext triggerCtx = getAlarmDMC(element); + if (triggerCtx == null) return ""; + DsfSession session = DsfSession.getSession(triggerCtx.getSessionId()); + if (session == null) return ""; - /* - * Create the query to request the value from service. - * Note: no need to guard against RejectedExecutionException, because - * DsfSession.getSession() above would only return an active session. - */ - GetValueQuery query = new GetValueQuery(dmc); - session.getExecutor().execute(query); + // Create the query to request the value from service. + GetValueQuery query = new GetValueQuery(triggerCtx); + try { + session.getExecutor().execute(query); + } catch (RejectedExecutionException e) { + return ""; + } try { return query.get().toString(); } catch (InterruptedException e) { assert false; - return ""; //$NON-NLS-1$ + return ""; } catch (ExecutionException e) { - return ""; //$NON-NLS-1$ + return ""; } } @@ -91,7 +89,7 @@ public class AlarmCellModifier implements ICellModifier { public void modify(Object element, String property, Object value) { if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return; - AlarmDMC dmc = getAlarmDMC(element); + TriggerDMContext dmc = getAlarmDMC(element); if (dmc == null) return; DsfSession session = DsfSession.getSession(dmc.getSessionId()); if (session == null) return; @@ -105,31 +103,32 @@ public class AlarmCellModifier implements ICellModifier { try { intValue = new Integer(((String)value).trim()); } catch (NumberFormatException e) { - MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); //$NON-NLS-1$ //$NON-NLS-2$ + MessageDialog.openError(shell, "Invalid Value", + "Please enter a positive integer"); return; } if (intValue.intValue() <= 0) { - MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); //$NON-NLS-1$ //$NON-NLS-2$ + MessageDialog.openError(shell, "Invalid Value", + "Please enter a positive integer"); return; } } - /* - * Create the query to write the value to the service. - * Note: no need to guard against RejectedExecutionException, because - * DsfSession.getSession() above would only return an active session. - */ + // Create the query to write the value to the service. SetValueQuery query = new SetValueQuery(dmc, intValue); - session.getExecutor().execute(query); - + try { + session.getExecutor().execute(query); + } catch (RejectedExecutionException e) { + // View must be shutting down, no need to show error dialog. + } try { // Return value is irrelevant, any error would come through with an exception. query.get().toString(); } catch (InterruptedException e) { assert false; } catch (ExecutionException e) { - // View must be shutting down, no need to show erro dialog. + // View must be shutting down, no need to show error dialog. } } @@ -151,15 +150,16 @@ public class AlarmCellModifier implements ICellModifier { return null; } - private AlarmDMC getAlarmDMC(Object element) { + private TriggerDMContext getAlarmDMC(Object element) { if (element instanceof IAdaptable) { - return (AlarmDMC)((IAdaptable)element).getAdapter(AlarmDMC.class); + return (TriggerDMContext)((IAdaptable)element).getAdapter(TriggerDMContext.class); } return null; } @ThreadSafe - private synchronized AlarmService getService(AlarmDMC dmc) { + private synchronized AlarmService getService(TriggerDMContext dmc) { + // Create and initialize the service tracker if needed. String serviceId = DsfServices.createServiceFilter( AlarmService.class, fSession.getId() ); if (fServiceTracker == null) { try { @@ -172,26 +172,25 @@ public class AlarmCellModifier implements ICellModifier { return null; } } + // Get the service. return (AlarmService)fServiceTracker.getService(); } + private class GetValueQuery extends Query { + final TriggerDMContext fDmc; - final AlarmDMC fDmc; - - private GetValueQuery(AlarmDMC dmc) { + private GetValueQuery(TriggerDMContext dmc) { super(); fDmc = dmc; } @Override protected void execute(final DataRequestMonitor rm) { - /* - * Guard against the session being disposed. If session is disposed - * it could mean that the executor is shut-down, which in turn - * could mean that we can't execute the "done" argument. - * In that case, cancel to notify waiting thread. - */ + // Guard against the session being disposed. If session is disposed + // it could mean that the executor is shut-down, which in turn + // could mean that we can't execute the "done" argument. + // In that case, cancel to notify waiting thread. final DsfSession session = DsfSession.getSession(fDmc.getSessionId()); if (session == null) { cancel(false); @@ -201,34 +200,30 @@ public class AlarmCellModifier implements ICellModifier { AlarmService service = getService(fDmc); if (service == null) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, - "Service not available", null)); //$NON-NLS-1$ + "Service not available", null)); + rm.done(); return; } - service.getAlarmData(fDmc, new DataRequestMonitor(session.getExecutor(), rm) { - @Override - protected void handleCompleted() { - // We're in another dispatch, so we must guard against executor shutdown again. - if (DsfSession.isSessionActive(session.getId())) { - super.handleCompleted(); - } - } - - @Override - protected void handleOK() { - rm.setData(getData().getTriggeringValue()); - rm.done(); - } - }); + int value = service.getTriggerValue(fDmc); + if (value == -1) { + rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, + "Invalid context", null)); + rm.done(); + return; + } + + rm.setData(value); + rm.done(); } } private class SetValueQuery extends Query { - AlarmDMC fDmc; + TriggerDMContext fDmc; int fValue; - SetValueQuery(AlarmDMC dmc, int value) { + SetValueQuery(TriggerDMContext dmc, int value) { super(); fDmc = dmc; fValue = value; @@ -247,13 +242,13 @@ public class AlarmCellModifier implements ICellModifier { AlarmService service = getService(fDmc); if (service == null) { rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, - "Service not available", null)); //$NON-NLS-1$ + "Service not available", null)); rm.done(); return; } // Finally set the value and return. - service.setAlarmValue(fDmc, fValue); + service.setTriggerValue(fDmc, fValue); // Return value is irrelevant. rm.setData(new Object()); diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggersVMNode.java b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggersVMNode.java new file mode 100644 index 00000000000..9934e2e8d6e --- /dev/null +++ b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/TriggersVMNode.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.examples.dsf.timers; + +import java.text.MessageFormat; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider; +import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage; +import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText; +import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider; +import org.eclipse.dd.examples.dsf.DsfExamplesPlugin; +import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.widgets.Composite; + + +/** + * View model node that defines how alarm DMContexts are displayed in the view. Alarm + * nodes are fairly static, once they are created their label doesn't change. + * @see TriggerDMContext + */ +@SuppressWarnings("restriction") +class TriggersVMNode extends AbstractDMVMNode + implements IElementEditor, IElementPropertiesProvider, IElementLabelProvider +{ + private static final String PROP_TRIGGER_NUMBER = "alarmNumber"; + private static final String PROP_TRIGGER_VALUE = "alarmTriggerValue"; + + // Create and configure the label provider. + private static final PropertyBasedLabelProvider fgLabelProvider; + static { + fgLabelProvider = new PropertyBasedLabelProvider(); + + LabelColumnInfo idCol = new LabelColumnInfo( + new LabelAttribute[] { + new LabelText(new MessageFormat("Trigger #{0}"), + new String[] { PROP_TRIGGER_NUMBER }), + new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry(). + getDescriptor(DsfExamplesPlugin.IMG_ALARM)) + }); + fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol); + + LabelColumnInfo valueCol = new LabelColumnInfo( + new LabelAttribute[] { + new LabelText(new MessageFormat("{0}"), + new String[] { PROP_TRIGGER_VALUE }) + }); + fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE, + valueCol); + } + + private TriggerCellModifier fAlarmCellModifier; + + public TriggersVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, TriggerDMContext.class); + } + + @Override + protected void updateElementsInSessionThread(final IChildrenUpdate update) { + if (!checkService(AlarmService.class, null, update)) return; + + TriggerDMContext[] triggers = + getServicesTracker().getService(AlarmService.class).getTriggers(); + fillUpdateWithVMCs(update, triggers); + update.done(); + } + + public void update(ILabelUpdate[] updates) { + fgLabelProvider.update(updates); + } + + public void update(final IPropertiesUpdate[] updates) { + // Switch to the session thread before processing the updates. + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + for (IPropertiesUpdate update : updates) { + updatePropertiesInSessionThread(update); + } + }}); + } catch (RejectedExecutionException e) { + for (IViewerUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + @ConfinedToDsfExecutor("getSession#getExecutor") + private void updatePropertiesInSessionThread(final IPropertiesUpdate update) { + // Find the trigger context in the element being updated + TriggerDMContext triggerCtx = findDmcInPath( + update.getViewerInput(), update.getElementPath(), TriggerDMContext.class); + + // If either update or service are not valid, fail the update and exit. + if (!checkDmc(triggerCtx, update) || + !checkService(AlarmService.class, null, update)) + { + return; + } + + // Calculate and set the update properties. + AlarmService alarmService = + getServicesTracker().getService(AlarmService.class, null); + int value = alarmService.getTriggerValue(triggerCtx); + + if (value == -1) { + handleFailedUpdate(update); + return; + } + + update.setProperty(PROP_TRIGGER_NUMBER, triggerCtx.getTriggerNumber()); + update.setProperty(PROP_TRIGGER_VALUE, value); + update.done(); + } + + public CellEditor getCellEditor(IPresentationContext context, String columnId, + Object element, Composite parent) + { + // Create a cell editor to modify the trigger value. + if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) { + return new TextCellEditor(parent); + } + return null; + } + + // Note: this method is synchronized because IElementEditor.getCellModifier can be called + // on any thread, even though in practice it should be only called on the UI thread. + public ICellModifier getCellModifier(IPresentationContext context, + Object element) + { + // Create the cell modifier if needed. + if (fAlarmCellModifier == null) { + fAlarmCellModifier = new TriggerCellModifier(getSession()); + } + return fAlarmCellModifier; + } + + public int getDeltaFlags(Object e) { + // Since the label for triggers doesn't change, this node will generate + // delta info only if the list of alarms is changed. + if (e instanceof AlarmService.TriggersChangedEvent) { + return IModelDelta.CONTENT; + } + return IModelDelta.NO_CHANGE; + } + + + public void buildDelta(Object event, VMDelta parentDelta, int nodeOffset, + RequestMonitor requestMonitor) + { + if (event instanceof AlarmService.TriggersChangedEvent) { + // The list of alarms has changed, which means that the parent + // node needs to refresh its contents, which in turn will re-fetch the + // elements from this node. + parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); + } + requestMonitor.done(); + } + + @Override + public void dispose() { + if (fAlarmCellModifier != null) { + fAlarmCellModifier.dispose(); + } + super.dispose(); + } + + public String getPropertyDescription(String property) { + return null; + } + + public String getPropertyName(String property) { + return null; + } +} diff --git a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/package.html b/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/package.html deleted file mode 100644 index a4b276be052..00000000000 --- a/plugins/org.eclipse.dd.examples.dsf/src/org/eclipse/dd/examples/dsf/timers/package.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - Eclipse Device Debug - Debugger Services Framework - Data Model - - -Example demostrationg use of Debugger Services Framework (DSF) data -model interfaces.
-

Package Specification

-The example consists of two services, one that monitors a set of timers -(TimerService), and another that tracks a set of alarms -(AlarmService).  The timers are incremented at a rate of one per -second, although for visual interest, timers are not synchronous as -each timer is incremented at a slightly different moment.  There -is also a "Timers" view that displays the timers and alarms, and has -actions for adding and removing new timers and alarms.  Most -interestingly, the view has a toggle action, which switches the layout -of the view from having timers at the root level, with alarms listed -below each timer, to having alarms at the root level with timers listed -below each alarm.
-
-
-
- -