]> git.basschouten.com Git - openhab-addons.git/blob
0de5d62a78a97a23aa39c0bef8172ec469ab419d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor;
14
15 import java.util.HashMap;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
24 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
25 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
26 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
29 import org.openhab.core.common.ThreadPoolManager;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * The {@link AbstractSensorJobExecutor} provides the working process to execute implementations of {@link SensorJob}'s
35  * in the time interval set at the {@link Config}.
36  * <p>
37  * The following methods can be overridden by subclasses to implement an execution priority:
38  * </p>
39  * <ul>
40  * <li>{@link #addLowPriorityJob(SensorJob)}</li>
41  * <li>{@link #addMediumPriorityJob(SensorJob)}</li>
42  * <li>{@link #addHighPriorityJob(SensorJob)}</li>
43  * </ul>
44  *
45  * @author Michael Ochel - Initial contribution
46  * @author Matthias Siegele - Initial contribution
47  *
48  */
49 public abstract class AbstractSensorJobExecutor {
50
51     private final Logger logger = LoggerFactory.getLogger(AbstractSensorJobExecutor.class);
52
53     private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
54     private Map<DSID, ScheduledFuture<?>> pollingSchedulers;
55
56     private final DsAPI dSAPI;
57     protected Config config;
58     private final ConnectionManager connectionManager;
59
60     private final List<CircuitScheduler> circuitSchedulerList = new LinkedList<>();
61
62     private class ExecutorRunnable implements Runnable {
63         private final CircuitScheduler circuit;
64
65         public ExecutorRunnable(CircuitScheduler circuit) {
66             this.circuit = circuit;
67         }
68
69         @Override
70         public void run() {
71             // pollingSchedulers is not final and might be set to null by another thread. See #8214
72             Map<DSID, ScheduledFuture<?>> pollingSchedulers = AbstractSensorJobExecutor.this.pollingSchedulers;
73
74             SensorJob sensorJob = circuit.getNextSensorJob();
75             DSID meter = circuit.getMeterDSID();
76
77             if (sensorJob != null) {
78                 sensorJob.execute(dSAPI, connectionManager.getSessionToken());
79             }
80             if (circuit.noMoreJobs() && pollingSchedulers != null) {
81                 logger.debug("no more jobs... stop circuit schedduler with id = {}", meter);
82                 ScheduledFuture<?> scheduler = pollingSchedulers.get(meter);
83                 if (scheduler != null) {
84                     scheduler.cancel(true);
85                 }
86             }
87         }
88     }
89
90     /**
91      * Creates a new {@link AbstractSensorJobExecutor}.
92      *
93      * @param connectionManager must not be null
94      */
95     public AbstractSensorJobExecutor(ConnectionManager connectionManager) {
96         this.connectionManager = connectionManager;
97         config = connectionManager.getConfig();
98         this.dSAPI = connectionManager.getDigitalSTROMAPI();
99     }
100
101     /**
102      * Stops all circuit schedulers.
103      */
104     public synchronized void shutdown() {
105         if (pollingSchedulers != null) {
106             for (ScheduledFuture<?> scheduledExecutor : pollingSchedulers.values()) {
107                 scheduledExecutor.cancel(true);
108             }
109             pollingSchedulers = null;
110             logger.debug("stop all circuit schedulers.");
111         }
112     }
113
114     /**
115      * Starts all circuit schedulers.
116      */
117     public synchronized void startExecutor() {
118         logger.debug("start all circuit schedulers.");
119         if (pollingSchedulers == null) {
120             pollingSchedulers = new HashMap<>();
121         }
122         if (circuitSchedulerList != null && !circuitSchedulerList.isEmpty()) {
123             for (CircuitScheduler circuit : circuitSchedulerList) {
124                 startSchedduler(circuit);
125             }
126         }
127     }
128
129     private void startSchedduler(CircuitScheduler circuit) {
130         if (pollingSchedulers != null) {
131             if (pollingSchedulers.get(circuit.getMeterDSID()) == null
132                     || pollingSchedulers.get(circuit.getMeterDSID()).isCancelled()) {
133                 pollingSchedulers.put(circuit.getMeterDSID(),
134                         scheduler.scheduleWithFixedDelay(new ExecutorRunnable(circuit), circuit.getNextExecutionDelay(),
135                                 config.getSensorReadingWaitTime(), TimeUnit.MILLISECONDS));
136             }
137         }
138     }
139
140     /**
141      * Adds a high priority {@link SensorJob}.
142      *
143      * @param sensorJob to add
144      */
145     public void addHighPriorityJob(SensorJob sensorJob) {
146         // can be Overridden to implement a priority
147         addSensorJobToCircuitScheduler(sensorJob);
148     }
149
150     /**
151      * Adds a medium priority {@link SensorJob}.
152      *
153      * @param sensorJob to add
154      */
155     public void addMediumPriorityJob(SensorJob sensorJob) {
156         // can be overridden to implement a priority
157         addSensorJobToCircuitScheduler(sensorJob);
158     }
159
160     /**
161      * Adds a low priority {@link SensorJob}.
162      *
163      * @param sensorJob to add
164      */
165     public void addLowPriorityJob(SensorJob sensorJob) {
166         // can be overridden to implement a priority
167         addSensorJobToCircuitScheduler(sensorJob);
168     }
169
170     /**
171      * Adds a {@link SensorJob} with a given priority .
172      *
173      * @param sensorJob to add
174      * @param priority to update
175      */
176     public void addPriorityJob(SensorJob sensorJob, long priority) {
177         if (sensorJob == null) {
178             return;
179         }
180         sensorJob.setInitalisationTime(priority);
181         addSensorJobToCircuitScheduler(sensorJob);
182         logger.debug("Add SensorJob from device with dSID {} and priority {} to AbstractJobExecutor",
183                 sensorJob.getDSID(), priority);
184     }
185
186     /**
187      * Adds the given {@link SensorJob}.
188      *
189      * @param sensorJob to add
190      */
191     protected void addSensorJobToCircuitScheduler(SensorJob sensorJob) {
192         synchronized (this.circuitSchedulerList) {
193             CircuitScheduler circuit = getCircuitScheduler(sensorJob.getMeterDSID());
194             if (circuit != null) {
195                 circuit.addSensorJob(sensorJob);
196             } else {
197                 circuit = new CircuitScheduler(sensorJob, config);
198                 this.circuitSchedulerList.add(circuit);
199             }
200             startSchedduler(circuit);
201         }
202     }
203
204     private CircuitScheduler getCircuitScheduler(DSID dsid) {
205         for (CircuitScheduler circuit : this.circuitSchedulerList) {
206             if (circuit.getMeterDSID().equals(dsid)) {
207                 return circuit;
208             }
209         }
210         return null;
211     }
212
213     /**
214      * Removes all SensorJobs of a specific {@link Device}.
215      *
216      * @param device to remove
217      */
218     public void removeSensorJobs(Device device) {
219         if (device != null) {
220             CircuitScheduler circuit = getCircuitScheduler(device.getMeterDSID());
221             if (circuit != null) {
222                 circuit.removeSensorJob(device.getDSID());
223             }
224         }
225     }
226
227     /**
228      * Removes the {@link SensorJob} with the given ID.
229      *
230      * @param device needed for the meterDSID
231      * @param ID of the {@link SensorJob} to remove
232      */
233     public void removeSensorJob(Device device, String ID) {
234         if (device != null && ID != null) {
235             CircuitScheduler circuit = getCircuitScheduler(device.getMeterDSID());
236             if (circuit != null) {
237                 circuit.removeSensorJob(ID);
238             }
239         }
240     }
241 }