X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fnet%2Fpterodactylus%2Fjsite%2Fcore%2FNodeManager.java;h=971d5c514ac11f29c72248873c83dbf087d6c224;hb=7e16d0a3b4f15da04f665fc011f78af2bc93a13d;hp=84867cda4f504b62236340f27ec76bb59a94d9c0;hpb=4be8c6526b4e80d5b8f8df8598da128be766ced7;p=jSite2.git diff --git a/src/net/pterodactylus/jsite/core/NodeManager.java b/src/net/pterodactylus/jsite/core/NodeManager.java index 84867cd..971d5c5 100644 --- a/src/net/pterodactylus/jsite/core/NodeManager.java +++ b/src/net/pterodactylus/jsite/core/NodeManager.java @@ -25,10 +25,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -39,17 +41,18 @@ import java.util.logging.Logger; import net.pterodactylus.fcp.highlevel.HighLevelClient; import net.pterodactylus.fcp.highlevel.HighLevelClientListener; import net.pterodactylus.util.io.Closer; +import net.pterodactylus.util.logging.Logging; /** * TODO - * + * * @author David ‘Bombe’ Roden <bombe@freenetproject.org> * @version $Id$ */ -public class NodeManager implements HighLevelClientListener { +public class NodeManager implements Iterable, HighLevelClientListener { /** Logger. */ - private static final Logger logger = Logger.getLogger(NodeManager.class.getName()); + private static final Logger logger = Logging.getLogger(NodeManager.class.getName()); /** The FCP client name. */ private final String clientName; @@ -77,7 +80,7 @@ public class NodeManager implements HighLevelClientListener { /** * Creates a new FCP collector. - * + * * @param clientName * The name of the FCP client * @param directory @@ -94,7 +97,7 @@ public class NodeManager implements HighLevelClientListener { /** * Adds the given listener to the list of listeners. - * + * * @param nodeListener * The listener to add */ @@ -104,7 +107,7 @@ public class NodeManager implements HighLevelClientListener { /** * Removes the given listener from the list of listeners. - * + * * @param nodeListener * The listener to remove */ @@ -113,8 +116,32 @@ public class NodeManager implements HighLevelClientListener { } /** + * Notifies all listeners that a node was added. + * + * @param node + * The node that was added. + */ + private void fireNodeAdded(Node node) { + for (NodeListener nodeListener: nodeListeners) { + nodeListener.nodeAdded(node); + } + } + + /** + * Notifies all listeners that a node was removed. + * + * @param node + * The node that was removed + */ + private void fireNodeRemoved(Node node) { + for (NodeListener nodeListener: nodeListeners) { + nodeListener.nodeRemoved(node); + } + } + + /** * Notifies all listeners that the given node was connected. - * + * * @param node * The node that is now connected */ @@ -126,7 +153,7 @@ public class NodeManager implements HighLevelClientListener { /** * Notifies all listeners that the given node was disconnected. - * + * * @param node * The node that is now disconnected * @param throwable @@ -145,7 +172,7 @@ public class NodeManager implements HighLevelClientListener { /** * Returns the directory in which the nodes are stored. - * + * * @return The directory the nodes are stored in */ public String getDirectory() { @@ -154,7 +181,7 @@ public class NodeManager implements HighLevelClientListener { /** * Checks whether the given node is already connected. - * + * * @param node * The node to check * @return true if the node is already connected, @@ -164,13 +191,20 @@ public class NodeManager implements HighLevelClientListener { return nodes.contains(node); } + /** + * {@inheritDoc} + */ + public Iterator iterator() { + return nodes.iterator(); + } + // // ACTIONS // /** * Loads nodes. - * + * * @throws IOException * if an I/O error occurs loading the nodes */ @@ -221,15 +255,18 @@ public class NodeManager implements HighLevelClientListener { newNode.setPort(nodePort); loadedNodes.add(newNode); } + logger.fine("loaded " + loadedNodes.size() + " nodes from config"); synchronized (syncObject) { nodes.clear(); - nodes.addAll(loadedNodes); + for (Node node: nodes) { + addNode(node); + } } } /** * Saves all configured nodes. - * + * * @throws IOException * if an I/O error occurs saving the nodes */ @@ -260,15 +297,22 @@ public class NodeManager implements HighLevelClientListener { /** * Adds the given node to this manager. - * + * * @see #connect(Node) * @param node * The node to connect to + * @throws UnknownHostException + * if the hostname of the node can not be resolved */ - public void addNode(Node node) { + public void addNode(Node node) throws UnknownHostException { synchronized (syncObject) { if (!nodes.contains(node)) { + HighLevelClient highLevelClient= new HighLevelClient(clientName, node.getHostname(), node.getPort()); nodes.add(node); + clientNodes.put(highLevelClient, node); + nodeClients.put(node, highLevelClient); + highLevelClient.addHighLevelClientListener(this); + fireNodeAdded(node); } } } @@ -276,7 +320,7 @@ public class NodeManager implements HighLevelClientListener { /** * Removes the given node from the node manager, disconnecting it if it is * currently connected. - * + * * @param node * The node to remove */ @@ -288,23 +332,22 @@ public class NodeManager implements HighLevelClientListener { if (nodeClients.containsKey(node)) { disconnect(node); } + fireNodeRemoved(node); } } /** * Tries to establish a connection with the given node. - * + * * @param node * The node to connect to */ public void connect(Node node) { + HighLevelClient highLevelClient; + synchronized (syncObject) { + highLevelClient = nodeClients.get(node); + } try { - HighLevelClient highLevelClient = new HighLevelClient(clientName, node.getHostname(), node.getPort()); - synchronized (syncObject) { - clientNodes.put(highLevelClient, node); - nodeClients.put(node, highLevelClient); - } - highLevelClient.addHighLevelClientListener(this); highLevelClient.connect(); } catch (IOException ioe1) { fireNodeDisconnected(node, ioe1); @@ -313,7 +356,7 @@ public class NodeManager implements HighLevelClientListener { /** * Disconnects the given node without removing it. - * + * * @param node * The node to disconnect */ @@ -329,13 +372,63 @@ public class NodeManager implements HighLevelClientListener { /** * Returns a list of all nodes. - * + * * @return A list of all nodes */ public List getNodes() { return Collections.unmodifiableList(nodes); } + /** + * “Borrows” a high-level client for the given node. A borrowed client + * has to be returned to the node manager using + * {@link #returnHighLevelClient(HighLevelClient)} when it is no longer in + * use, i.e. after a message has been sent! This method will block until a + * high-level client for the given node is available. + * + * @param node + * The node to get a high-level client for + * @return The high-level client for a node, or null if the + * node was disconnected or removed + */ + public HighLevelClient borrowHighLevelClient(Node node) { + synchronized (syncObject) { + if (!nodeClients.containsKey(node)) { + return null; + } + HighLevelClient highLevelClient = nodeClients.get(node); + while (nodeClients.containsKey(node) && usedConnections.contains(highLevelClient)) { + try { + syncObject.wait(); + } catch (InterruptedException ie1) { + /* ignore. TODO - check. */ + } + } + if (!nodeClients.containsKey(node)) { + return null; + } + usedConnections.add(highLevelClient); + return highLevelClient; + } + } + + /** + * Returns a borrowed high-level client. + * + * @see #borrowHighLevelClient(Node) + * @param highLevelClient + * The high-level client to return + */ + public void returnHighLevelClient(HighLevelClient highLevelClient) { + synchronized (syncObject) { + if (!clientNodes.containsKey(highLevelClient)) { + return; + } + usedConnections.remove(highLevelClient); + syncObject.notifyAll(); + } + } + // // PRIVATE METHODS // @@ -343,7 +436,7 @@ public class NodeManager implements HighLevelClientListener { /** * Finds a currently unused high-level client, optionally waiting until a * client is free and marking it used. - * + * * @param wait * true to wait for a free connection, * false to return null @@ -373,6 +466,11 @@ public class NodeManager implements HighLevelClientListener { if (!wait) { return null; } + try { + syncObject.wait(); + } catch (InterruptedException e) { + /* ignore, just re-check. */ + } } /* we never get here, but the compiler doesn't realize. */ return null; @@ -387,6 +485,7 @@ public class NodeManager implements HighLevelClientListener { * {@inheritDoc} */ public void clientConnected(HighLevelClient highLevelClient) { + logger.log(Level.FINER, "clientConnected(c=" + highLevelClient + ")"); Node node = clientNodes.get(highLevelClient); if (node == null) { logger.log(Level.WARNING, "got event for unknown client"); @@ -399,6 +498,7 @@ public class NodeManager implements HighLevelClientListener { * {@inheritDoc} */ public void clientDisconnected(HighLevelClient highLevelClient, Throwable throwable) { + logger.log(Level.FINER, "clientDisconnected(c=" + highLevelClient + ",t=" + throwable + ")"); synchronized (syncObject) { Node node = clientNodes.remove(highLevelClient); if (node == null) { @@ -406,6 +506,7 @@ public class NodeManager implements HighLevelClientListener { return; } nodeClients.remove(node); + usedConnections.remove(highLevelClient); fireNodeDisconnected(node, throwable); } }