All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.wizard.mvc.ping.model.PingTableModel Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.mvc.ping.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;

import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.event.ConsoleMessageEvent;
import org.bidib.wizard.api.service.console.ConsoleColor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jgoodies.binding.beans.Model;
import com.jgoodies.common.collect.ArrayListModel;

public class PingTableModel extends Model {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LoggerFactory.getLogger(PingTableModel.class);

    public static final String PROPERTY_NODES = "nodes";

    public static final String PROPERTY_NODE_PING_STATUS = "nodePingStatus";

    private ArrayListModel nodeList = new ArrayListModel<>();

    private final PropertyChangeListener pclNodePingModel;

    private int defaultPingInterval = 200;

    private final PingTablePreferences pingTablePreferences;

    public PingTableModel(final PingTablePreferences pingTablePreferences) {
        this.pingTablePreferences = pingTablePreferences;

        pclNodePingModel = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                LOGGER.info("The property of the node ping model has changed: {}", evt.getSource());

                if (evt.getSource() instanceof NodePingModel) {
                    NodePingModel nodePingModel = (NodePingModel) evt.getSource();

                    switch (evt.getPropertyName()) {
                        case NodePingModel.PROPERTY_NODE_PING_STATUS:
                            firePropertyChange(PROPERTY_NODE_PING_STATUS, null, nodePingModel.getNode());
                            break;
                        case NodePingModel.PROPERTY_PING_INTERVAL:
                            try {
                                PingTableNodePreferenceEntry prefs =
                                    PingTableModel.this.pingTablePreferences
                                        .getPrefencesOrDefault(nodePingModel.getNode().getUniqueId());
                                prefs.setPingInterval(nodePingModel.getPingInterval());
                                PingTableModel.this.pingTablePreferences.store();
                            }
                            catch (Exception ex) {
                                LOGGER.warn("Store ping table preferences failed.", ex);
                            }
                            break;
                        case NodePingModel.PROPERTY_ADDITIONAL_FILL_BYTES_COUNT:
                            try {
                                PingTableNodePreferenceEntry prefs =
                                    PingTableModel.this.pingTablePreferences
                                        .getPrefencesOrDefault(nodePingModel.getNode().getUniqueId());
                                prefs.setAdditionalFillBytesCount(nodePingModel.getAdditionalFillBytesCount());
                                PingTableModel.this.pingTablePreferences.store();
                            }
                            catch (Exception ex) {
                                LOGGER.warn("Store ping table preferences failed.", ex);
                            }
                            break;
                        case NodePingModel.PROPERTY_ADDITIONAL_TOTAL_BYTES_COUNT:
                            try {
                                PingTableNodePreferenceEntry prefs =
                                    PingTableModel.this.pingTablePreferences
                                        .getPrefencesOrDefault(nodePingModel.getNode().getUniqueId());
                                prefs.setAdditionalTotalBytesCount(nodePingModel.getAdditionalTotalBytesCount());
                                PingTableModel.this.pingTablePreferences.store();
                            }
                            catch (Exception ex) {
                                LOGGER.warn("Store ping table preferences failed.", ex);
                            }
                            break;
                        case NodePingModel.PROPERTY_IDENTIFY_PROCESSING_WAIT_DURATION:
                            try {
                                PingTableNodePreferenceEntry prefs =
                                    PingTableModel.this.pingTablePreferences
                                        .getPrefencesOrDefault(nodePingModel.getNode().getUniqueId());
                                prefs
                                    .setIdentityProcessingWaitDuration(
                                        nodePingModel.getIdentifyProcessingWaitDuration());
                                PingTableModel.this.pingTablePreferences.store();
                            }
                            catch (Exception ex) {
                                LOGGER.warn("Store ping table preferences failed.", ex);
                            }
                            break;
                        default:
                            break;
                    }

                }
            }
        };
    }

    /**
     * Set the default ping interval.
     * 
     * @param pingInterval
     *            the default ping interval
     */
    public void setDefaultPingInterval(int pingInterval) {
        LOGGER.info("Set the defaultPingInterval: {}", pingInterval);
        this.defaultPingInterval = pingInterval;
    }

    public void addNode(final NodeInterface node) {
        synchronized (nodeList) {
            NodePingModel nodePingModel = new NodePingModel(node);
            if (!nodeList.contains(nodePingModel)) {
                LOGGER.info("Add node to ping node list: {}", node);
                nodePingModel.registerNode();

                // set the default interval
                nodePingModel.setPingInterval(this.defaultPingInterval);
                nodePingModel.setLastPingTimestamp(System.currentTimeMillis());
                nodePingModel.setNodePingState(NodePingState.OFF);
                String nodeLabel = nodePingModel.prepareNodeLabel();
                nodePingModel.setNodeLabel(nodeLabel);

                // check if we have preferences for this node
                PingTableNodePreferenceEntry prefs = this.pingTablePreferences.getPrefences(node.getUniqueId());
                if (prefs != null) {

                    nodePingModel.setPingInterval(prefs.getPingInterval());
                    nodePingModel.setAdditionalFillBytesCount(prefs.getAdditionalFillBytesCount());
                    nodePingModel.setAdditionalTotalBytesCount(prefs.getAdditionalTotalBytesCount());
                    nodePingModel.setAdditionalPayloadStartValue(prefs.getAdditionalPayloadStartValue());
                    nodePingModel.setIdentifyProcessingWaitDuration(prefs.getIdentityProcessingWaitDuration());
                }

                List oldValue = new LinkedList<>(nodeList);
                nodeList.add(nodePingModel);

                firePropertyChange(PROPERTY_NODES, oldValue, nodeList);

                nodePingModel
                    .addPropertyChangeListener(/* NodePingModel.PROPERTY_NODE_PING_STATUS, */ pclNodePingModel);
            }
            else {
                LOGGER.warn("Node is already in ping node list: {}", node);
            }
        }
    }

    public void removeNode(final NodeInterface node) {
        synchronized (nodeList) {
            LOGGER.info("Remove node from ping node list: {}", node);

            List oldValue = new LinkedList<>(nodeList);
            int index = nodeList.indexOf(new NodePingModel(node));
            if (index > -1) {
                NodePingModel removed = nodeList.remove(index);
                LOGGER.info("Removed node: {}", removed);

                removed.removePropertyChangeListener(/* NodePingModel.PROPERTY_NODE_PING_STATUS, */ pclNodePingModel);

                if (removed != null) {
                    removed.freeNode();
                }

                firePropertyChange(PROPERTY_NODES, oldValue, nodeList);
            }
        }
    }

    public ArrayListModel getNodeListModel() {
        return nodeList;
    }

    public List getNodes() {
        return Collections.unmodifiableList(nodeList);
    }

    public void setNodePingState(final NodeInterface node, NodePingState nodePingState) {
        synchronized (nodeList) {
            int index = nodeList.indexOf(new NodePingModel(node));
            if (index > -1) {
                NodePingModel nodePingModel = nodeList.get(index);
                if (nodePingModel != null) {
                    nodePingModel.setNodePingState(nodePingState);

                    // firePropertyChange(PROPERTY_NODE_PING_STATUS, null, node);
                }
            }
        }
    }

    public void setPongMarker(byte[] address, int marker, final Consumer consoleCallback) {

        final NodePingModel pingModel;
        synchronized (nodeList) {
            pingModel =
                nodeList
                    .stream().filter(npm -> Arrays.equals(address, npm.getNode().getAddr())).findFirst().orElse(null);
        }

        if (pingModel != null) {
            long lastPongMarker = pingModel.getLastPongMarker();
            if (lastPongMarker < 0) {
                // invalid marker, ignore evaluation
            }
            else {
                // check if the pong marker is correct
                lastPongMarker += 1;
                if (lastPongMarker > 255) {
                    lastPongMarker = 0;
                }
                if (marker != lastPongMarker) {
                    LOGGER.warn("Invalid pong marker detected. Received: {}, expected: {}", marker, lastPongMarker);

                    // prepare the console message event
                    final ConsoleMessageEvent consoleMessageEvent =
                        new ConsoleMessageEvent(ConsoleColor.red,
                            "Invalid pong marker detected. Received: " + marker + ", expected: " + lastPongMarker);
                    consoleCallback.accept(consoleMessageEvent);
                }
                else {
                    LOGGER.info("The pong marker is valid! Received: {}, expected: {}", marker, lastPongMarker);
                }
            }

            // update the last pong marker
            pingModel.setLastPongMarker(marker);
        }
    }

    public void checkIdentifyWaitTime(byte[] address) {

        final NodePingModel pingModel;
        synchronized (nodeList) {
            pingModel =
                nodeList
                    .stream().filter(npm -> Arrays.equals(address, npm.getNode().getAddr())).findFirst().orElse(null);
        }

        if (pingModel != null) {
            int identifyProcessingWaitDuration = pingModel.getIdentifyProcessingWaitDuration();
            if (identifyProcessingWaitDuration > 0) {
                LOGGER
                    .info("Simulate long duration for processing, identifyProcessingWaitDuration: {}",
                        identifyProcessingWaitDuration);

                try {
                    Thread.sleep(identifyProcessingWaitDuration);

                    LOGGER.info("identifyProcessingWaitDuration elapsed.");
                }
                catch (Exception ex) {
                    LOGGER.warn("Wait for expiration of identifyProcessingWaitDuration failed.", ex);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy