mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[insteon] Convert legacy threads to use scheduler service (#17904)
Signed-off-by: jsetton <jeremy.setton@gmail.com>
This commit is contained in:
parent
29915c434c
commit
a94e4a1c50
@ -36,8 +36,6 @@ import org.openhab.binding.insteon.internal.device.LegacyDevice.DeviceStatus;
|
|||||||
import org.openhab.binding.insteon.internal.device.LegacyDeviceFeature;
|
import org.openhab.binding.insteon.internal.device.LegacyDeviceFeature;
|
||||||
import org.openhab.binding.insteon.internal.device.LegacyDeviceType;
|
import org.openhab.binding.insteon.internal.device.LegacyDeviceType;
|
||||||
import org.openhab.binding.insteon.internal.device.LegacyDeviceTypeLoader;
|
import org.openhab.binding.insteon.internal.device.LegacyDeviceTypeLoader;
|
||||||
import org.openhab.binding.insteon.internal.device.LegacyPollManager;
|
|
||||||
import org.openhab.binding.insteon.internal.device.LegacyRequestManager;
|
|
||||||
import org.openhab.binding.insteon.internal.device.X10Address;
|
import org.openhab.binding.insteon.internal.device.X10Address;
|
||||||
import org.openhab.binding.insteon.internal.device.database.LegacyModemDBEntry;
|
import org.openhab.binding.insteon.internal.device.database.LegacyModemDBEntry;
|
||||||
import org.openhab.binding.insteon.internal.device.feature.LegacyFeatureListener;
|
import org.openhab.binding.insteon.internal.device.feature.LegacyFeatureListener;
|
||||||
@ -269,7 +267,7 @@ public class InsteonLegacyBinding implements LegacyDriverListener, LegacyPortLis
|
|||||||
int ndev = checkIfInModemDatabase(device);
|
int ndev = checkIfInModemDatabase(device);
|
||||||
if (device.hasModemDBEntry()) {
|
if (device.hasModemDBEntry()) {
|
||||||
device.setStatus(DeviceStatus.POLLING);
|
device.setStatus(DeviceStatus.POLLING);
|
||||||
LegacyPollManager.instance().startPolling(device, ndev);
|
driver.getPollManager().startPolling(device, ndev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
devices.put(address, device);
|
devices.put(address, device);
|
||||||
@ -286,7 +284,7 @@ public class InsteonLegacyBinding implements LegacyDriverListener, LegacyPortLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (device.getStatus() == DeviceStatus.POLLING) {
|
if (device.getStatus() == DeviceStatus.POLLING) {
|
||||||
LegacyPollManager.instance().stopPolling(device);
|
driver.getPollManager().stopPolling(device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,8 +348,6 @@ public class InsteonLegacyBinding implements LegacyDriverListener, LegacyPortLis
|
|||||||
logger.debug("shutting down Insteon bridge");
|
logger.debug("shutting down Insteon bridge");
|
||||||
driver.stop();
|
driver.stop();
|
||||||
devices.clear();
|
devices.clear();
|
||||||
LegacyRequestManager.destroyInstance();
|
|
||||||
LegacyPollManager.instance().stop();
|
|
||||||
isActive = false;
|
isActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +423,7 @@ public class InsteonLegacyBinding implements LegacyDriverListener, LegacyPortLis
|
|||||||
|
|
||||||
public void logDeviceStatistics() {
|
public void logDeviceStatistics() {
|
||||||
String msg = String.format("devices: %3d configured, %3d polling, msgs received: %5d", devices.size(),
|
String msg = String.format("devices: %3d configured, %3d polling, msgs received: %5d", devices.size(),
|
||||||
LegacyPollManager.instance().getSizeOfQueue(), messagesReceived);
|
driver.getPollManager().getSizeOfQueue(), messagesReceived);
|
||||||
logger.debug("{}", msg);
|
logger.debug("{}", msg);
|
||||||
messagesReceived = 0;
|
messagesReceived = 0;
|
||||||
for (LegacyDevice device : devices.values()) {
|
for (LegacyDevice device : devices.values()) {
|
||||||
@ -485,7 +481,7 @@ public class InsteonLegacyBinding implements LegacyDriverListener, LegacyPortLis
|
|||||||
device.setHasModemDBEntry(true);
|
device.setHasModemDBEntry(true);
|
||||||
}
|
}
|
||||||
if (device.getStatus() != DeviceStatus.POLLING) {
|
if (device.getStatus() != DeviceStatus.POLLING) {
|
||||||
LegacyPollManager.instance().startPolling(device, dbes.size());
|
driver.getPollManager().startPolling(device, dbes.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,11 +263,9 @@ public class LegacyDevice {
|
|||||||
mrequestQueue.add(qe);
|
mrequestQueue.add(qe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LegacyRequestManager instance = LegacyRequestManager.instance();
|
LegacyDriver driver = this.driver;
|
||||||
if (instance != null) {
|
if (driver != null) {
|
||||||
instance.addQueue(this, now + delay);
|
driver.getRequestManager().addQueue(this, now + delay);
|
||||||
} else {
|
|
||||||
logger.warn("request queue manager is null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list.isEmpty()) {
|
if (!list.isEmpty()) {
|
||||||
@ -388,11 +386,9 @@ public class LegacyDevice {
|
|||||||
msg.setQuietTime(QUIET_TIME_DIRECT_MESSAGE);
|
msg.setQuietTime(QUIET_TIME_DIRECT_MESSAGE);
|
||||||
}
|
}
|
||||||
logger.trace("enqueing direct message with delay {}", delay);
|
logger.trace("enqueing direct message with delay {}", delay);
|
||||||
LegacyRequestManager instance = LegacyRequestManager.instance();
|
LegacyDriver driver = this.driver;
|
||||||
if (instance != null) {
|
if (driver != null) {
|
||||||
instance.addQueue(this, now + delay);
|
driver.getRequestManager().addQueue(this, now + delay);
|
||||||
} else {
|
|
||||||
logger.warn("request queue manger instance is null");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,12 @@ import java.sql.Date;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.insteon.internal.InsteonBindingConstants;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -45,16 +47,16 @@ public class LegacyPollManager {
|
|||||||
private static final long MIN_MSEC_BETWEEN_POLLS = 2000L;
|
private static final long MIN_MSEC_BETWEEN_POLLS = 2000L;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(LegacyPollManager.class);
|
private final Logger logger = LoggerFactory.getLogger(LegacyPollManager.class);
|
||||||
private static LegacyPollManager poller = new LegacyPollManager(); // for singleton
|
|
||||||
|
|
||||||
private @Nullable Thread pollThread = null;
|
private ScheduledExecutorService scheduler;
|
||||||
|
private @Nullable ScheduledFuture<?> job;
|
||||||
private TreeSet<PQEntry> pollQueue = new TreeSet<>();
|
private TreeSet<PQEntry> pollQueue = new TreeSet<>();
|
||||||
private boolean keepRunning = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
private LegacyPollManager() {
|
public LegacyPollManager(ScheduledExecutorService scheduler) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,17 +106,8 @@ public class LegacyPollManager {
|
|||||||
* Starts the poller thread
|
* Starts the poller thread
|
||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
if (pollThread == null) {
|
if (job == null) {
|
||||||
pollThread = new Thread(new PollQueueReader());
|
job = scheduler.schedule(new PollQueueReader(), 0, TimeUnit.SECONDS);
|
||||||
setParamsAndStart(pollThread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setParamsAndStart(@Nullable Thread thread) {
|
|
||||||
if (thread != null) {
|
|
||||||
thread.setName("OH-binding-" + InsteonBindingConstants.BINDING_ID + "-pollQueueReader");
|
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,21 +115,10 @@ public class LegacyPollManager {
|
|||||||
* Stops the poller thread
|
* Stops the poller thread
|
||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop() {
|
||||||
logger.debug("stopping poller!");
|
ScheduledFuture<?> job = this.job;
|
||||||
synchronized (pollQueue) {
|
if (job != null) {
|
||||||
pollQueue.clear();
|
job.cancel(true);
|
||||||
keepRunning = false;
|
this.job = null;
|
||||||
pollQueue.notify();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread pollThread = this.pollThread;
|
|
||||||
if (pollThread != null) {
|
|
||||||
pollThread.join();
|
|
||||||
this.pollThread = null;
|
|
||||||
}
|
|
||||||
keepRunning = true;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.debug("got interrupted on exit: {}", e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,18 +186,17 @@ public class LegacyPollManager {
|
|||||||
private class PollQueueReader implements Runnable {
|
private class PollQueueReader implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.debug("starting poll thread.");
|
logger.debug("starting poll queue thread");
|
||||||
synchronized (pollQueue) {
|
try {
|
||||||
while (keepRunning) {
|
while (!Thread.interrupted()) {
|
||||||
try {
|
synchronized (pollQueue) {
|
||||||
readPollQueue();
|
readPollQueue();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.warn("poll queue reader thread interrupted!");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.trace("poll queue thread interrupted!");
|
||||||
}
|
}
|
||||||
logger.debug("poll thread exiting");
|
logger.debug("exiting poll queue thread!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,10 +206,9 @@ public class LegacyPollManager {
|
|||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
private void readPollQueue() throws InterruptedException {
|
private void readPollQueue() throws InterruptedException {
|
||||||
while (pollQueue.isEmpty() && keepRunning) {
|
if (pollQueue.isEmpty()) {
|
||||||
|
logger.trace("waiting for poll queue to fill");
|
||||||
pollQueue.wait();
|
pollQueue.wait();
|
||||||
}
|
|
||||||
if (!keepRunning) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// something is in the queue
|
// something is in the queue
|
||||||
@ -297,14 +277,4 @@ public class LegacyPollManager {
|
|||||||
return device.getAddress().toString() + "/" + String.format("%tc", new Date(expirationTime));
|
return device.getAddress().toString() + "/" + String.format("%tc", new Date(expirationTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton pattern instance() method
|
|
||||||
*
|
|
||||||
* @return the poller instance
|
|
||||||
*/
|
|
||||||
public static synchronized LegacyPollManager instance() {
|
|
||||||
poller.start();
|
|
||||||
return poller;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,12 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.insteon.internal.InsteonBindingConstants;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -39,24 +41,18 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LegacyRequestManager {
|
public class LegacyRequestManager {
|
||||||
private static @Nullable LegacyRequestManager instance = null;
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(LegacyRequestManager.class);
|
private final Logger logger = LoggerFactory.getLogger(LegacyRequestManager.class);
|
||||||
private @Nullable Thread queueThread = null;
|
|
||||||
|
private ScheduledExecutorService scheduler;
|
||||||
|
private @Nullable ScheduledFuture<?> job;
|
||||||
private Queue<RequestQueue> requestQueues = new PriorityQueue<>();
|
private Queue<RequestQueue> requestQueues = new PriorityQueue<>();
|
||||||
private Map<LegacyDevice, RequestQueue> requestQueueHash = new HashMap<>();
|
private Map<LegacyDevice, RequestQueue> requestQueueHash = new HashMap<>();
|
||||||
private boolean keepRunning = true;
|
|
||||||
|
|
||||||
private LegacyRequestManager() {
|
/**
|
||||||
queueThread = new Thread(new RequestQueueReader());
|
* Constructor
|
||||||
setParamsAndStart(queueThread);
|
*/
|
||||||
}
|
public LegacyRequestManager(ScheduledExecutorService scheduler) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
private void setParamsAndStart(@Nullable Thread thread) {
|
|
||||||
if (thread != null) {
|
|
||||||
thread.setName("OH-binding-" + InsteonBindingConstants.BINDING_ID + "-requestQueueReader");
|
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,25 +88,23 @@ public class LegacyRequestManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts request queue thread
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
if (job == null) {
|
||||||
|
job = scheduler.schedule(new RequestQueueReader(), 0, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops request queue thread
|
* Stops request queue thread
|
||||||
*/
|
*/
|
||||||
private void stopThread() {
|
public void stop() {
|
||||||
logger.debug("stopping thread");
|
ScheduledFuture<?> job = this.job;
|
||||||
Thread queueThread = this.queueThread;
|
if (job != null) {
|
||||||
if (queueThread != null) {
|
job.cancel(true);
|
||||||
synchronized (requestQueues) {
|
this.job = null;
|
||||||
keepRunning = false;
|
|
||||||
requestQueues.notifyAll();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
logger.debug("waiting for thread to join");
|
|
||||||
queueThread.join();
|
|
||||||
logger.debug("request queue thread exited!");
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.warn("got interrupted waiting for thread exit ", e);
|
|
||||||
}
|
|
||||||
this.queueThread = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,11 +112,16 @@ public class LegacyRequestManager {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.debug("starting request queue thread");
|
logger.debug("starting request queue thread");
|
||||||
synchronized (requestQueues) {
|
try {
|
||||||
while (keepRunning) {
|
while (!Thread.interrupted()) {
|
||||||
try {
|
synchronized (requestQueues) {
|
||||||
RequestQueue queue;
|
if (requestQueues.isEmpty()) {
|
||||||
while (keepRunning && (queue = requestQueues.peek()) != null) {
|
logger.trace("waiting for request queues to fill");
|
||||||
|
requestQueues.wait();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RequestQueue queue = requestQueues.peek();
|
||||||
|
if (queue != null) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long expTime = queue.getExpirationTime();
|
long expTime = queue.getExpirationTime();
|
||||||
LegacyDevice device = queue.getDevice();
|
LegacyDevice device = queue.getDevice();
|
||||||
@ -150,13 +149,10 @@ public class LegacyRequestManager {
|
|||||||
logger.debug("device queue for {} is empty!", device.getAddress());
|
logger.debug("device queue for {} is empty!", device.getAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.trace("waiting for request queues to fill");
|
|
||||||
requestQueues.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.warn("request queue thread got interrupted, breaking..", e);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.trace("request queue thread interrupted!");
|
||||||
}
|
}
|
||||||
logger.debug("exiting request queue thread!");
|
logger.debug("exiting request queue thread!");
|
||||||
}
|
}
|
||||||
@ -188,19 +184,4 @@ public class LegacyRequestManager {
|
|||||||
return (int) (expirationTime - queue.expirationTime);
|
return (int) (expirationTime - queue.expirationTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized @Nullable LegacyRequestManager instance() {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new LegacyRequestManager();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void destroyInstance() {
|
|
||||||
LegacyRequestManager instance = LegacyRequestManager.instance;
|
|
||||||
if (instance != null) {
|
|
||||||
instance.stopThread();
|
|
||||||
LegacyRequestManager.instance = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ public class PollManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.debug("poll queue thread interrupted!");
|
logger.trace("poll queue thread interrupted!");
|
||||||
}
|
}
|
||||||
logger.debug("exiting poll queue thread!");
|
logger.debug("exiting poll queue thread!");
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ public class RequestManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.debug("request queue thread interrupted!");
|
logger.trace("request queue thread interrupted!");
|
||||||
}
|
}
|
||||||
logger.debug("exiting request queue thread!");
|
logger.debug("exiting request queue thread!");
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.insteon.internal.config.InsteonLegacyNetworkConfiguration;
|
import org.openhab.binding.insteon.internal.config.InsteonLegacyNetworkConfiguration;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
|
import org.openhab.binding.insteon.internal.device.LegacyPollManager;
|
||||||
|
import org.openhab.binding.insteon.internal.device.LegacyRequestManager;
|
||||||
import org.openhab.binding.insteon.internal.device.database.LegacyModemDBEntry;
|
import org.openhab.binding.insteon.internal.device.database.LegacyModemDBEntry;
|
||||||
import org.openhab.binding.insteon.internal.transport.message.Msg;
|
import org.openhab.binding.insteon.internal.transport.message.Msg;
|
||||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||||
@ -37,6 +39,8 @@ import org.openhab.core.io.transport.serial.SerialPortManager;
|
|||||||
public class LegacyDriver {
|
public class LegacyDriver {
|
||||||
private LegacyPort port;
|
private LegacyPort port;
|
||||||
private LegacyDriverListener listener;
|
private LegacyDriverListener listener;
|
||||||
|
private LegacyPollManager poller;
|
||||||
|
private LegacyRequestManager requester;
|
||||||
private Map<InsteonAddress, LegacyModemDBEntry> modemDBEntries = new HashMap<>();
|
private Map<InsteonAddress, LegacyModemDBEntry> modemDBEntries = new HashMap<>();
|
||||||
private ReentrantLock modemDBEntriesLock = new ReentrantLock();
|
private ReentrantLock modemDBEntriesLock = new ReentrantLock();
|
||||||
|
|
||||||
@ -45,6 +49,8 @@ public class LegacyDriver {
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
||||||
this.port = new LegacyPort(config, this, serialPortManager, scheduler);
|
this.port = new LegacyPort(config, this, serialPortManager, scheduler);
|
||||||
|
this.poller = new LegacyPollManager(scheduler);
|
||||||
|
this.requester = new LegacyRequestManager(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
@ -70,10 +76,14 @@ public class LegacyDriver {
|
|||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
port.start();
|
port.start();
|
||||||
|
poller.start();
|
||||||
|
requester.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
port.stop();
|
port.stop();
|
||||||
|
poller.stop();
|
||||||
|
requester.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMessage(Msg m) throws IOException {
|
public void writeMessage(Msg m) throws IOException {
|
||||||
@ -105,4 +115,12 @@ public class LegacyDriver {
|
|||||||
public void disconnected() {
|
public void disconnected() {
|
||||||
listener.disconnected();
|
listener.disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LegacyPollManager getPollManager() {
|
||||||
|
return poller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LegacyRequestManager getRequestManager() {
|
||||||
|
return requester;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,12 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.insteon.internal.InsteonBindingConstants;
|
|
||||||
import org.openhab.binding.insteon.internal.InsteonLegacyBindingConstants;
|
import org.openhab.binding.insteon.internal.InsteonLegacyBindingConstants;
|
||||||
import org.openhab.binding.insteon.internal.config.InsteonLegacyNetworkConfiguration;
|
import org.openhab.binding.insteon.internal.config.InsteonLegacyNetworkConfiguration;
|
||||||
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
import org.openhab.binding.insteon.internal.device.InsteonAddress;
|
||||||
@ -74,11 +75,11 @@ public class LegacyPort {
|
|||||||
private IOStream ioStream;
|
private IOStream ioStream;
|
||||||
private String name;
|
private String name;
|
||||||
private Modem modem;
|
private Modem modem;
|
||||||
|
private ScheduledExecutorService scheduler;
|
||||||
private IOStreamReader reader;
|
private IOStreamReader reader;
|
||||||
private IOStreamWriter writer;
|
private IOStreamWriter writer;
|
||||||
private final int readSize = 1024; // read buffer size
|
private @Nullable ScheduledFuture<?> readJob;
|
||||||
private @Nullable Thread readThread = null;
|
private @Nullable ScheduledFuture<?> writeJob;
|
||||||
private @Nullable Thread writeThread = null;
|
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
private boolean modemDBComplete = false;
|
private boolean modemDBComplete = false;
|
||||||
private MsgFactory msgFactory = new MsgFactory();
|
private MsgFactory msgFactory = new MsgFactory();
|
||||||
@ -100,6 +101,7 @@ public class LegacyPort {
|
|||||||
SerialPortManager serialPortManager, ScheduledExecutorService scheduler) {
|
SerialPortManager serialPortManager, ScheduledExecutorService scheduler) {
|
||||||
this.name = config.getRedactedPort();
|
this.name = config.getRedactedPort();
|
||||||
this.driver = driver;
|
this.driver = driver;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.modem = new Modem();
|
this.modem = new Modem();
|
||||||
addListener(modem);
|
addListener(modem);
|
||||||
this.ioStream = IOStream.create(config.parse(), scheduler, serialPortManager);
|
this.ioStream = IOStream.create(config.parse(), scheduler, serialPortManager);
|
||||||
@ -178,10 +180,8 @@ public class LegacyPort {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
readThread = new Thread(reader);
|
readJob = scheduler.schedule(reader, 0, TimeUnit.SECONDS);
|
||||||
setParamsAndStart(readThread, "OH-binding-" + InsteonBindingConstants.BINDING_ID + "-LegacyReader");
|
writeJob = scheduler.schedule(writer, 0, TimeUnit.SECONDS);
|
||||||
writeThread = new Thread(writer);
|
|
||||||
setParamsAndStart(writeThread, "OH-binding-" + InsteonBindingConstants.BINDING_ID + "-LegacyWriter");
|
|
||||||
|
|
||||||
if (!mdbb.isComplete()) {
|
if (!mdbb.isComplete()) {
|
||||||
modem.initialize();
|
modem.initialize();
|
||||||
@ -192,14 +192,6 @@ public class LegacyPort {
|
|||||||
disconnected.set(false);
|
disconnected.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setParamsAndStart(@Nullable Thread thread, String type) {
|
|
||||||
if (thread != null) {
|
|
||||||
thread.setName("OH-binding-Insteon " + name + " " + type);
|
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops all threads
|
* Stops all threads
|
||||||
*/
|
*/
|
||||||
@ -219,32 +211,17 @@ public class LegacyPort {
|
|||||||
ioStream.close();
|
ioStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread readThread = this.readThread;
|
ScheduledFuture<?> readJob = this.readJob;
|
||||||
if (readThread != null) {
|
if (readJob != null) {
|
||||||
readThread.interrupt();
|
readJob.cancel(true);
|
||||||
|
this.readJob = null;
|
||||||
}
|
}
|
||||||
Thread writeThread = this.writeThread;
|
|
||||||
if (writeThread != null) {
|
ScheduledFuture<?> writeJob = this.writeJob;
|
||||||
writeThread.interrupt();
|
if (writeJob != null) {
|
||||||
|
writeJob.cancel(true);
|
||||||
|
this.writeJob = null;
|
||||||
}
|
}
|
||||||
logger.debug("waiting for read thread to exit for port {}", name);
|
|
||||||
try {
|
|
||||||
if (readThread != null) {
|
|
||||||
readThread.join();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.debug("got interrupted waiting for read thread to exit.");
|
|
||||||
}
|
|
||||||
logger.debug("waiting for write thread to exit for port {}", name);
|
|
||||||
try {
|
|
||||||
if (writeThread != null) {
|
|
||||||
writeThread.join();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.debug("got interrupted waiting for write thread to exit.");
|
|
||||||
}
|
|
||||||
this.readThread = null;
|
|
||||||
this.writeThread = null;
|
|
||||||
|
|
||||||
logger.debug("all threads for port {} stopped.", name);
|
logger.debug("all threads for port {} stopped.", name);
|
||||||
}
|
}
|
||||||
@ -296,6 +273,7 @@ public class LegacyPort {
|
|||||||
* @author Bernd Pfrommer - Initial contribution
|
* @author Bernd Pfrommer - Initial contribution
|
||||||
*/
|
*/
|
||||||
class IOStreamReader implements Runnable {
|
class IOStreamReader implements Runnable {
|
||||||
|
private static final int READ_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
private ReplyType reply = ReplyType.GOT_ACK;
|
private ReplyType reply = ReplyType.GOT_ACK;
|
||||||
private Object replyLock = new Object();
|
private Object replyLock = new Object();
|
||||||
@ -311,20 +289,25 @@ public class LegacyPort {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.debug("starting reader...");
|
logger.debug("starting reader thread");
|
||||||
byte[] buffer = new byte[readSize];
|
byte[] buffer = new byte[READ_BUFFER_SIZE];
|
||||||
try {
|
try {
|
||||||
for (int len = -1; (len = ioStream.read(buffer)) > 0;) {
|
while (!Thread.interrupted()) {
|
||||||
msgFactory.addData(buffer, len);
|
logger.trace("reader checking for input data");
|
||||||
processMessages();
|
// this call blocks until input data is available
|
||||||
|
int len = ioStream.read(buffer);
|
||||||
|
if (len > 0) {
|
||||||
|
msgFactory.addData(buffer, len);
|
||||||
|
processMessages();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.debug("reader thread got interrupted!");
|
logger.trace("reader thread got interrupted!");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("got an io exception in the reader thread");
|
logger.trace("reader thread got an io exception", e);
|
||||||
disconnected();
|
disconnected();
|
||||||
}
|
}
|
||||||
logger.debug("reader thread exiting!");
|
logger.debug("exiting reader thread!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMessages() {
|
private void processMessages() {
|
||||||
@ -389,28 +372,22 @@ public class LegacyPort {
|
|||||||
* Called by IOStreamWriter for flow control.
|
* Called by IOStreamWriter for flow control.
|
||||||
*
|
*
|
||||||
* @return true if retransmission is necessary
|
* @return true if retransmission is necessary
|
||||||
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
public boolean waitForReply() {
|
public boolean waitForReply() throws InterruptedException {
|
||||||
reply = ReplyType.WAITING_FOR_ACK;
|
reply = ReplyType.WAITING_FOR_ACK;
|
||||||
while (reply == ReplyType.WAITING_FOR_ACK) {
|
logger.trace("writer waiting for ack.");
|
||||||
try {
|
// There have been cases observed, in particular for
|
||||||
logger.trace("writer waiting for ack.");
|
// the Hub, where we get no ack or nack back, causing the binding
|
||||||
// There have been cases observed, in particular for
|
// to hang in the wait() below, because unsolicited messages
|
||||||
// the Hub, where we get no ack or nack back, causing the binding
|
// do not trigger a notify(). For this reason we request retransmission
|
||||||
// to hang in the wait() below, because unsolicited messages
|
// if the wait() times out.
|
||||||
// do not trigger a notify(). For this reason we request retransmission
|
getRequestReplyLock().wait(30000); // be patient for 30 msec
|
||||||
// if the wait() times out.
|
if (reply == ReplyType.WAITING_FOR_ACK) { // timeout expired without getting ACK or NACK
|
||||||
getRequestReplyLock().wait(30000); // be patient for 30 msec
|
logger.trace("writer timeout expired, asking for retransmit!");
|
||||||
if (reply == ReplyType.WAITING_FOR_ACK) { // timeout expired without getting ACK or NACK
|
reply = ReplyType.GOT_NACK;
|
||||||
logger.trace("writer timeout expired, asking for retransmit!");
|
} else {
|
||||||
reply = ReplyType.GOT_NACK;
|
logger.trace("writer got ack: {}", (reply == ReplyType.GOT_ACK));
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
logger.trace("writer got ack: {}", (reply == ReplyType.GOT_ACK));
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
break; // done for the day...
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return reply == ReplyType.GOT_NACK;
|
return reply == ReplyType.GOT_NACK;
|
||||||
}
|
}
|
||||||
@ -427,9 +404,9 @@ public class LegacyPort {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logger.debug("starting writer...");
|
logger.debug("starting writer thread");
|
||||||
while (true) {
|
try {
|
||||||
try {
|
while (!Thread.interrupted()) {
|
||||||
// this call blocks until the lock on the queue is released
|
// this call blocks until the lock on the queue is released
|
||||||
logger.trace("writer checking message queue");
|
logger.trace("writer checking message queue");
|
||||||
Msg msg = writeQueue.take();
|
Msg msg = writeQueue.take();
|
||||||
@ -450,16 +427,14 @@ public class LegacyPort {
|
|||||||
if (msg.getQuietTime() > 0) {
|
if (msg.getQuietTime() > 0) {
|
||||||
Thread.sleep(msg.getQuietTime());
|
Thread.sleep(msg.getQuietTime());
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.debug("got interrupted exception in write thread");
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.debug("got an io exception in the write thread");
|
|
||||||
disconnected();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.trace("writer thread got interrupted!");
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.trace("writer thread got an io exception", e);
|
||||||
|
disconnected();
|
||||||
}
|
}
|
||||||
logger.debug("writer thread exiting!");
|
logger.debug("exiting writer thread!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +233,9 @@ public class Port {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.debug("reader thread got interrupted!");
|
logger.trace("reader thread got interrupted!");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("reader thread got an io exception", e);
|
logger.trace("reader thread got an io exception", e);
|
||||||
disconnected();
|
disconnected();
|
||||||
}
|
}
|
||||||
logger.debug("exiting reader thread!");
|
logger.debug("exiting reader thread!");
|
||||||
@ -333,9 +333,9 @@ public class Port {
|
|||||||
Thread.sleep(WRITE_WAIT_TIME);
|
Thread.sleep(WRITE_WAIT_TIME);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
logger.debug("writer thread got interrupted!");
|
logger.trace("writer thread got interrupted!");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("writer thread got an io exception", e);
|
logger.trace("writer thread got an io exception", e);
|
||||||
disconnected();
|
disconnected();
|
||||||
}
|
}
|
||||||
logger.debug("exiting writer thread!");
|
logger.debug("exiting writer thread!");
|
||||||
|
Loading…
Reference in New Issue
Block a user