]> git.basschouten.com Git - openhab-addons.git/blob
979ff023763949208019ef893394db125045565e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.dsmr.internal.device;
14
15 import java.util.concurrent.Semaphore;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.openhab.binding.dsmr.internal.device.connector.DSMRConnectorErrorEvent;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * The {@link DSMRDeviceRunnable} runs a {@link DSMRDevice} and blocks until it is restarted or shutdown. If it is
24  * restarted it will restart the {@link DSMRDevice}. If it is shutdown the run will end. By using a semaphore to restart
25  * and shutdown this class handles the actual {@link DSMRDevice}, while threads calling restart and shutdown can finish
26  * fast.
27  *
28  * @author Hilbrand Bouwkamp - Initial contribution
29  */
30 @NonNullByDefault
31 public class DSMRDeviceRunnable implements Runnable {
32     private final Logger logger = LoggerFactory.getLogger(DSMRDeviceRunnable.class);
33     private final Semaphore semaphore = new Semaphore(0);
34     private final DSMRDevice device;
35     private final DSMREventListener portEventListener;
36
37     /**
38      * Keeps state of running. If false run will stop.
39      */
40     private boolean running;
41
42     /**
43      * Constructor
44      *
45      * @param device the device to control
46      * @param eventListener listener to used ot report errors.
47      */
48     public DSMRDeviceRunnable(DSMRDevice device, DSMREventListener eventListener) {
49         this.device = device;
50         this.portEventListener = eventListener;
51     }
52
53     /**
54      * Sets state to restart the dsmr device.
55      */
56     public void restart() {
57         releaseSemaphore();
58     }
59
60     /**
61      * Sets state to shutdown the dsmr device.
62      */
63     public void stop() {
64         running = false;
65         releaseSemaphore();
66     }
67
68     /**
69      * Controls the dsmr device. Runs until shutdown.
70      */
71     @Override
72     public void run() {
73         try {
74             running = true;
75             device.start();
76             while (running && !Thread.interrupted()) {
77                 semaphore.acquire();
78                 // Just drain all other permits to make sure it's not called twice
79                 semaphore.drainPermits();
80                 if (running) {
81                     logger.trace("Restarting device");
82                     device.restart();
83                 }
84             }
85             logger.trace("Device shutdown");
86         } catch (RuntimeException e) {
87             logger.warn("DSMRDeviceRunnable stopped with a RuntimeException", e);
88             portEventListener.handleErrorEvent(DSMRConnectorErrorEvent.READ_ERROR);
89         } catch (InterruptedException e) {
90             Thread.currentThread().interrupt();
91         } finally {
92             device.stop();
93         }
94     }
95
96     /**
97      * Wrapper around semaphore to only release when no permits available.
98      */
99     private void releaseSemaphore() {
100         synchronized (semaphore) {
101             if (semaphore.availablePermits() == 0) {
102                 semaphore.release();
103             }
104         }
105     }
106 }