package com.neemre.btcdcli4j.daemon; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.neemre.btcdcli4j.core.BitcoindException; import com.neemre.btcdcli4j.core.CommunicationException; import com.neemre.btcdcli4j.core.NodeProperties; import com.neemre.btcdcli4j.core.client.BtcdClient; import com.neemre.btcdcli4j.daemon.event.AlertListener; import com.neemre.btcdcli4j.daemon.event.BlockListener; import com.neemre.btcdcli4j.daemon.event.WalletListener; import com.neemre.btcdcli4j.daemon.notification.NotificationMonitor; public class BtcdDaemonImpl implements BtcdDaemon { private static final Logger LOG = LoggerFactory.getLogger(BtcdDaemonImpl.class); private DaemonConfigurator configurator; private Map<Notifications, NotificationMonitor> monitors; private Map<Notifications, Future<Void>> futures; private ExecutorService monitorPool; private BtcdClient client; public BtcdDaemonImpl() { this(new Properties()); } public BtcdDaemonImpl(BtcdClient btcdProvider) throws BitcoindException, CommunicationException { initialize(); this.client = configurator.checkBtcdProvider(btcdProvider); buildMonitors(configurator.checkNodeConfig(client.getNodeConfig())); configurator.checkNodeLiveness(client.getInfo()); startMonitors(); configurator.checkMonitorStates(futures); } public BtcdDaemonImpl(Properties nodeConfig) { initialize(); buildMonitors(configurator.checkNodeConfig(nodeConfig)); startMonitors(); configurator.checkMonitorStates(futures); } public BtcdDaemonImpl(Integer alertPort, Integer blockPort, Integer walletPort) { this(new DaemonConfigurator().toProperties(alertPort, blockPort, walletPort)); } @Override public void addAlertListener(AlertListener listener) { monitors.get(Notifications.ALERT).addObserver(listener.getObserver()); } @Override public int countAlertListeners() { return monitors.get(Notifications.ALERT).countObservers(); } @Override public void removeAlertListener(AlertListener listener) { monitors.get(Notifications.ALERT).deleteObserver(listener.getObserver()); } @Override public void removeAlertListeners() { monitors.get(Notifications.ALERT).deleteObservers(); } @Override public void addBlockListener(BlockListener listener) { monitors.get(Notifications.BLOCK).addObserver(listener.getObserver()); } @Override public int countBlockListeners() { return monitors.get(Notifications.BLOCK).countObservers(); } @Override public void removeBlockListener(BlockListener listener) { monitors.get(Notifications.BLOCK).deleteObserver(listener.getObserver()); } @Override public void removeBlockListeners() { monitors.get(Notifications.BLOCK).deleteObservers(); } @Override public void addWalletListener(WalletListener listener) { monitors.get(Notifications.WALLET).addObserver(listener.getObserver()); } @Override public int countWalletListeners() { return monitors.get(Notifications.WALLET).countObservers(); } @Override public void removeWalletListener(WalletListener listener) { monitors.get(Notifications.WALLET).deleteObserver(listener.getObserver()); } @Override public void removeWalletListeners() { monitors.get(Notifications.WALLET).deleteObservers(); } @Override public boolean isMonitoring(Notifications notificationType) { Future<Void> monitorHandle = futures.get(notificationType); if (monitorHandle != null) { return !monitorHandle.isDone(); } else { return false; } } @Override public boolean isMonitoringAny() { for (Notifications notificationType : Notifications.values()) { Future<Void> monitorHandle = futures.get(notificationType); if ((monitorHandle != null) && (!monitorHandle.isDone())) { return true; } } return false; } @Override public boolean isMonitoringAll() { for (Notifications notificationType : Notifications.values()) { Future<Void> monitorHandle = futures.get(notificationType); if ((monitorHandle == null) || (monitorHandle.isDone())) { return false; } } return true; } @Override public Properties getNodeConfig() { return configurator.getNodeConfig(); } @Override public synchronized void shutdown() { LOG.info(">> shutdown(..): shutting down the 'bitcoind' notification daemon"); monitorPool.shutdownNow(); } private void initialize() { LOG.info(">> initialize(..): initiating the 'bitcoind' notification daemon"); configurator = new DaemonConfigurator(); monitors = new HashMap<Notifications, NotificationMonitor>(); futures = new HashMap<Notifications, Future<Void>>(); } private void buildMonitors(Properties nodeConfig) { int alertPort = Integer.parseInt(nodeConfig.getProperty(NodeProperties.ALERT_PORT.getKey())); monitors.put(Notifications.ALERT, new NotificationMonitor(Notifications.ALERT, alertPort, null)); int blockPort = Integer.parseInt(nodeConfig.getProperty(NodeProperties.BLOCK_PORT.getKey())); monitors.put(Notifications.BLOCK, new NotificationMonitor(Notifications.BLOCK, blockPort, client)); int walletPort = Integer.parseInt(nodeConfig.getProperty(NodeProperties.WALLET_PORT.getKey())); monitors.put(Notifications.WALLET, new NotificationMonitor(Notifications.WALLET, walletPort, client)); monitorPool = Executors.newFixedThreadPool(monitors.size()); } private void startMonitors() { for (Notifications notificationType : monitors.keySet()) { NotificationMonitor monitor = monitors.get(notificationType); futures.put(notificationType, monitorPool.submit(monitor, (Void)null)); } } }