package com.rubiconproject.oss.kv.distributed; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public abstract class AbstractRefreshingNodeStore implements NodeStore { public static final Long DEFAULT_DELAY = 1000l * 60l; public static final Long DEFAULT_PERIOD = 1000l * 60l; protected Log log = LogFactory.getLog(getClass()); protected Properties props; protected List<NodeChangeListener> listeners = new LinkedList<NodeChangeListener>(); protected volatile List<Node> activeNodes = new LinkedList<Node>(); public void setProperties(Properties props) { this.props = props; } public void start() throws IOException, ConfigurationException { this.activeNodes = refreshActiveNodes(); publish(); schedule(DEFAULT_DELAY, DEFAULT_PERIOD); } public void schedule(long delay, long period) { Timer t = new Timer(true); t.scheduleAtFixedRate(new TimerTask() { public void run() { try { List<Node> newActiveNodes = refreshActiveNodes(); if (changed(activeNodes, newActiveNodes)) { activeNodes = newActiveNodes; publish(); } } catch (Exception e) { log.error("Exception calling refreshActiveNodes()", e); } } }, delay, period); } public void addChangeListener(NodeChangeListener listener) { this.listeners.add(listener); } public void addNode(Node node) { if (!this.activeNodes.contains(node)) { this.activeNodes.add(node); publish(); } } public void removeNode(Node node) { if (this.activeNodes.contains(node)) { this.activeNodes.remove(node); publish(); } } public List<Node> getActiveNodes() { return activeNodes; } public abstract List<Node> refreshActiveNodes() throws IOException, ConfigurationException; protected void publish() { activeNodes = getActiveNodes(); for (NodeChangeListener listener : listeners) { try { listener.setActiveNodes(activeNodes); } catch (Exception e) { log.warn("Exception calling activeNodes() on listener class.", e); } } } private boolean changed(List<Node> active, List<Node> updated) { if (active.size() != updated.size()) return true; for (int i = 0; i < active.size(); ++i) { Node currentNode = active.get(i); Node updatedNode = updated.get(i); // compare if ((currentNode.getId() != updatedNode.getId()) || (!currentNode.getConnectionURI().equals( updatedNode.getConnectionURI())) || (currentNode.getPhysicalId() != updatedNode .getPhysicalId()) || (!currentNode.getSalt().equals(updatedNode.getSalt()))) return true; } return false; } }