| /******************************************************************************* |
| * Copyright (c) 2006, 2009 Wind River Systems and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.examples.dsf.timers; |
| |
| import java.util.Hashtable; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| |
| import org.eclipse.cdt.dsf.concurrent.Immutable; |
| import org.eclipse.cdt.dsf.concurrent.RequestMonitor; |
| import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; |
| import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; |
| import org.eclipse.cdt.dsf.datamodel.DMContexts; |
| import org.eclipse.cdt.dsf.datamodel.IDMContext; |
| import org.eclipse.cdt.dsf.service.AbstractDsfService; |
| import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; |
| import org.eclipse.cdt.dsf.service.DsfSession; |
| import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin; |
| import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext; |
| import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerTickDMEvent; |
| import org.osgi.framework.BundleContext; |
| |
| /** |
| * 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. |
| * <p> |
| * This service depends on the TimerService, so the TimerService has to be |
| * initialized before this service is initialized. |
| * </p> |
| */ |
| public class AlarmService extends AbstractDsfService { |
| /** Event indicating that the list of triggers is changed. */ |
| @Immutable |
| public static class TriggersChangedEvent { |
| } |
| |
| /** Context representing an alarm tracked by this service. */ |
| @Immutable |
| public static class TriggerDMContext extends AbstractDMContext { |
| /** Alarm number, also index into alarm map */ |
| final int fNumber; |
| |
| private TriggerDMContext(String sessionId, int number) { |
| super(sessionId, new IDMContext[0]); |
| fNumber = number; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| return baseEquals(other) && ((TriggerDMContext) other).fNumber == fNumber; |
| } |
| |
| public int getTriggerNumber() { |
| return fNumber; |
| } |
| |
| @Override |
| public int hashCode() { |
| return baseHashCode() + fNumber; |
| } |
| |
| @Override |
| public String toString() { |
| return baseToString() + ".trigger[" + fNumber + "]"; |
| } |
| } |
| |
| /** |
| * Context representing the "triggered" status of an alarm with respect to |
| * a specific timer. |
| */ |
| @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(); |
| } |
| |
| @Override |
| public String toString() { |
| return baseToString() + ":alarm"; //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Event indicating that an alarm has been triggered by a timer. |
| */ |
| public class AlarmTriggeredDMEvent extends AbstractDMEvent<AlarmDMContext> { |
| public AlarmTriggeredDMEvent(AlarmDMContext context) { |
| super(context); |
| } |
| } |
| |
| private int fTriggerNumberCounter = 1; |
| private Map<TriggerDMContext, Integer> fTriggers = new LinkedHashMap<>(); |
| |
| AlarmService(DsfSession session) { |
| super(session); |
| } |
| |
| @Override |
| protected BundleContext getBundleContext() { |
| return DsfExamplesPlugin.getDefault().getBundle().getBundleContext(); |
| } |
| |
| @Override |
| public void initialize(final RequestMonitor requestMonitor) { |
| super.initialize(new RequestMonitor(getExecutor(), requestMonitor) { |
| @Override |
| protected void handleSuccess() { |
| // After super-class is finished initializing |
| // perform TimerService initialization. |
| doInitialize(requestMonitor); |
| } |
| }); |
| } |
| |
| 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<String, String>()); |
| |
| requestMonitor.done(); |
| } |
| |
| @Override |
| public void shutdown(RequestMonitor requestMonitor) { |
| getSession().removeServiceEventListener(this); |
| unregister(); |
| super.shutdown(requestMonitor); |
| } |
| |
| public boolean isValid() { |
| return true; |
| } |
| |
| @DsfServiceEventHandler |
| public void eventDispatched(TimerTickDMEvent event) { |
| final TimerDMContext timerContext = event.getDMContext(); |
| |
| 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); |
| } |
| |
| private void checkAlarmsForTimer(TimerDMContext timerContext, int timerValue) { |
| // Check the existing alarms for whether they are triggered by given |
| // timer. |
| for (Map.Entry<TriggerDMContext, Integer> entry : fTriggers.entrySet()) { |
| if (timerValue == entry.getValue()) { |
| // Generate the AlarmTriggeredEvent |
| AlarmDMContext alarmCtx = new AlarmDMContext(getSession().getId(), timerContext, entry.getKey()); |
| getSession().dispatchEvent(new AlarmTriggeredDMEvent(alarmCtx), getProperties()); |
| } |
| } |
| } |
| |
| /** 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; |
| } |
| } |
| |
| /** Returns the alarm context for given timer and trigger contexts. */ |
| public AlarmDMContext getAlarm(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); |
| } |
| |
| return false; |
| } |
| |
| /** 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 deleteTrigger(TriggerDMContext alarmCtx) { |
| fTriggers.remove(alarmCtx); |
| getSession().dispatchEvent(new TriggersChangedEvent(), getProperties()); |
| } |
| |
| /** 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 TriggersChangedEvent(), getProperties()); |
| } |
| } |