001package jmri.implementation; 002 003import java.util.*; 004 005import jmri.Meter; 006 007/** 008 * Handles updates of meters. Several meters may share the update task. 009 * 010 * @author Mark Underwood (C) 2015 011 * @author Daniel Bergqvist (C) 2020 012 */ 013public abstract class MeterUpdateTask { 014 015 Map<Meter, Boolean> meters = new HashMap<>(); 016 boolean _enabled = false; 017 private UpdateTask _intervalTask = null; 018 private int _initialInterval; //in ms 019 private int _sleepInterval; //in ms 020 021 /* default values for both sleepIntervals */ 022 public MeterUpdateTask() { 023 _sleepInterval = 10000; 024 _initialInterval = 10000; 025 } 026 027 /* if only one interval passed, set both to same */ 028 public MeterUpdateTask(int interval) { 029 _initialInterval = interval; 030 _sleepInterval = interval; 031 } 032 033 public MeterUpdateTask(int initialInterval, int sleepInterval) { 034 _initialInterval = initialInterval; 035 _sleepInterval = sleepInterval; 036 } 037 038 public void addMeter(Meter m) { 039 meters.put(m, false); 040 } 041 042 public void removeMeter(Meter m) { 043 meters.remove(m); 044 } 045 046 public void enable() { 047 if(_intervalTask != null) { 048 _intervalTask.enable(); 049 } else { 050 log.debug("_intervalTask is null, enable() ignored"); 051 } 052 } 053 054 public void enable(Meter m) { 055 if (!meters.containsKey(m)) { 056 throw new IllegalArgumentException("Meter is not registered"); 057 } 058 059 if (!meters.get(m)) { 060 meters.put(m, true); 061 if (!_enabled) { 062 _enabled = true; 063 enable(); 064 } 065 } 066 } 067 068 protected void disable() { 069 if(_intervalTask != null) { 070 _intervalTask.disable(); 071 } 072 } 073 074 public void disable(Meter m) { 075 if (!meters.containsKey(m)) return; 076 077 if (meters.get(m)) { 078 meters.put(m, false); 079 if (_enabled) { 080 // Is there any more meters that are active? 081 boolean found = false; 082 for (Boolean b : meters.values()) { 083 found |= b; 084 } 085 if (! found) { 086 _enabled = false; 087 disable(); 088 } 089 } 090 } 091 } 092 093 public void initTimer() { 094 if(_intervalTask != null) { 095 _intervalTask.cancel(); 096 _intervalTask = null; 097 } 098 if(_sleepInterval < 0){ 099 log.debug("_sleepInterval {} less than zero, initTimer() ignored", _sleepInterval); 100 return; // don't start or restart the timer. 101 } 102 _intervalTask = new UpdateTask(); 103 // At some point this will be dynamic intervals... 104 log.debug("Starting Meter Timer for {}ms, {}ms", _initialInterval, _sleepInterval); 105 jmri.util.TimerUtil.scheduleAtFixedRate(_intervalTask, 106 _initialInterval, _sleepInterval); 107 } 108 109 public abstract void requestUpdateFromLayout(); 110 111 /** 112 * Remove references to and from this object, so that it can eventually be 113 * garbage-collected. 114 * @param m the meter that is calling dispose 115 */ 116 public void dispose(Meter m){ 117 removeMeter(m); 118 if (meters.isEmpty() && (_intervalTask != null)) { 119 _intervalTask.cancel(); 120 _intervalTask = null; 121 } 122 } 123 124 125 // Timer task for periodic updates... 126 private class UpdateTask extends TimerTask { 127 128 private boolean _isEnabled = false; 129 130 public UpdateTask() { 131 super(); 132 } 133 134 public void enable() { 135 _isEnabled = true; 136 } 137 138 public void disable() { 139 _isEnabled = false; 140 } 141 142 @Override 143 public void run() { 144 if (_isEnabled) { 145 log.debug("UpdateTask requesting update from layout"); 146 requestUpdateFromLayout(); 147 } else { 148 log.debug("UpdateTask not enabled, run() ignored"); 149 } 150 } 151 } 152 153 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MeterUpdateTask.class); 154}