From 4be8c6526b4e80d5b8f8df8598da128be766ced7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sat, 3 May 2008 22:53:44 +0000 Subject: [PATCH] rework node connections git-svn-id: http://trooper/svn/projects/jSite/trunk@787 c3eda9e8-030b-0410-8277-bc7414b0a119 --- src/net/pterodactylus/jsite/core/NodeListener.java | 52 ++++++ src/net/pterodactylus/jsite/core/NodeManager.java | 176 +++++++++++++++++---- 2 files changed, 197 insertions(+), 31 deletions(-) create mode 100644 src/net/pterodactylus/jsite/core/NodeListener.java diff --git a/src/net/pterodactylus/jsite/core/NodeListener.java b/src/net/pterodactylus/jsite/core/NodeListener.java new file mode 100644 index 0000000..80a01ce --- /dev/null +++ b/src/net/pterodactylus/jsite/core/NodeListener.java @@ -0,0 +1,52 @@ +/* + * jSite2 - NodeListener.java - + * Copyright © 2008 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package net.pterodactylus.jsite.core; + +import java.util.EventListener; + +/** + * Interface for listeners that want to be notified about node events. + * + * @author David ‘Bombe’ Roden <bombe@freenetproject.org> + * @version $Id$ + */ +public interface NodeListener extends EventListener { + + /** + * Notifies a listener that a connection to the given node was established. + * + * @param node + * The node that is now connected + */ + public void nodeConnected(Node node); + + /** + * Notifies a listener that a connection to the given node was severed. The + * listener is responsible for + * + * @param node + * The node that is now disconnected + * @param throwable + * The exception that caused the disconnect, or null + * if there was no exception + */ + public void nodeDisconnected(Node node, Throwable throwable); + +} diff --git a/src/net/pterodactylus/jsite/core/NodeManager.java b/src/net/pterodactylus/jsite/core/NodeManager.java index 71bb95d..84867cd 100644 --- a/src/net/pterodactylus/jsite/core/NodeManager.java +++ b/src/net/pterodactylus/jsite/core/NodeManager.java @@ -25,7 +25,6 @@ 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; @@ -37,9 +36,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import net.pterodactylus.fcp.highlevel.ConnectResult; -import net.pterodactylus.fcp.highlevel.HighLevelCallback; import net.pterodactylus.fcp.highlevel.HighLevelClient; +import net.pterodactylus.fcp.highlevel.HighLevelClientListener; import net.pterodactylus.util.io.Closer; /** @@ -48,7 +46,7 @@ import net.pterodactylus.util.io.Closer; * @author David ‘Bombe’ Roden <bombe@freenetproject.org> * @version $Id$ */ -public class NodeManager { +public class NodeManager implements HighLevelClientListener { /** Logger. */ private static final Logger logger = Logger.getLogger(NodeManager.class.getName()); @@ -62,11 +60,14 @@ public class NodeManager { /** Object used for synchronization. */ private final Object syncObject = new Object(); + /** Node listeners. */ + private List nodeListeners = Collections.synchronizedList(new ArrayList()); + /** All nodes. */ private List nodes = Collections.synchronizedList(new ArrayList()); /** All FCP connections. */ - private Map nodeConnections = Collections.synchronizedMap(new HashMap()); + private Map nodeClients = Collections.synchronizedMap(new HashMap()); /** Keeps track of which connection is in use right now. */ private Set usedConnections = Collections.synchronizedSet(new HashSet()); @@ -88,6 +89,57 @@ public class NodeManager { } // + // EVENT MANAGEMENT + // + + /** + * Adds the given listener to the list of listeners. + * + * @param nodeListener + * The listener to add + */ + public void addNodeListener(NodeListener nodeListener) { + nodeListeners.add(nodeListener); + } + + /** + * Removes the given listener from the list of listeners. + * + * @param nodeListener + * The listener to remove + */ + public void removeNodeListener(NodeListener nodeListener) { + nodeListeners.remove(nodeListener); + } + + /** + * Notifies all listeners that the given node was connected. + * + * @param node + * The node that is now connected + */ + private void fireNodeConnected(Node node) { + for (NodeListener nodeListener: nodeListeners) { + nodeListener.nodeConnected(node); + } + } + + /** + * Notifies all listeners that the given node was disconnected. + * + * @param node + * The node that is now disconnected + * @param throwable + * The exception that caused the disconnect, or null + * if there was no exception + */ + private void fireNodeDisconnected(Node node, Throwable throwable) { + for (NodeListener nodeListener: nodeListeners) { + nodeListener.nodeDisconnected(node, throwable); + } + } + + // // ACCESSORS // @@ -207,41 +259,72 @@ public class NodeManager { } /** - * Adds a connection to the given node. The connection is made instantly so - * this method may block. If the node can not be connected, it will not be - * added to the list of nodes. + * Adds the given node to this manager. * + * @see #connect(Node) * @param node * The node to connect to - * @return true if the connection to the node could be - * established - * @throws UnknownHostException - * if the hostname of the node can not be resolved - * @throws IOException - * if an I/O error occurs connecting to the node */ - public boolean addNode(Node node) throws UnknownHostException, IOException { - if (nodes.contains(node)) { - return true; + public void addNode(Node node) { + synchronized (syncObject) { + if (!nodes.contains(node)) { + nodes.add(node); + } } - HighLevelClient highLevelClient = new HighLevelClient(clientName, node.getHostname(), node.getPort()); - HighLevelCallback connectCallback = highLevelClient.connect(); - ConnectResult connectResult = null; - while (connectResult == null) { - try { - connectResult = connectCallback.getResult(); - } catch (InterruptedException e) { - /* ignore. */ + } + + /** + * Removes the given node from the node manager, disconnecting it if it is + * currently connected. + * + * @param node + * The node to remove + */ + public void removeNode(Node node) { + synchronized (syncObject) { + if (!nodes.contains(node)) { + return; + } + if (nodeClients.containsKey(node)) { + disconnect(node); } } - if (connectResult.isConnected()) { + } + + /** + * Tries to establish a connection with the given node. + * + * @param node + * The node to connect to + */ + public void connect(Node node) { + try { + HighLevelClient highLevelClient = new HighLevelClient(clientName, node.getHostname(), node.getPort()); synchronized (syncObject) { - nodes.add(node); - nodeConnections.put(node, highLevelClient); clientNodes.put(highLevelClient, node); + nodeClients.put(node, highLevelClient); } + highLevelClient.addHighLevelClientListener(this); + highLevelClient.connect(); + } catch (IOException ioe1) { + fireNodeDisconnected(node, ioe1); + } + } + + /** + * Disconnects the given node without removing it. + * + * @param node + * The node to disconnect + */ + public void disconnect(Node node) { + synchronized (syncObject) { + if (!nodes.contains(node)) { + return; + } + HighLevelClient highLevelClient = nodeClients.get(node); + highLevelClient.disconnect(); } - return connectResult.isConnected(); } /** @@ -250,7 +333,7 @@ public class NodeManager { * @return A list of all nodes */ public List getNodes() { - return new ArrayList(clientNodes.values()); + return Collections.unmodifiableList(nodes); } // @@ -275,7 +358,7 @@ public class NodeManager { synchronized (syncObject) { HighLevelClient freeHighLevelClient = null; while (freeHighLevelClient == null) { - for (HighLevelClient highLevelClient: nodeConnections.values()) { + for (HighLevelClient highLevelClient: nodeClients.values()) { if (!usedConnections.contains(highLevelClient)) { freeHighLevelClient = highLevelClient; break; @@ -296,4 +379,35 @@ public class NodeManager { } } + // + // INTERFACE HighLevelClientListener + // + + /** + * {@inheritDoc} + */ + public void clientConnected(HighLevelClient highLevelClient) { + Node node = clientNodes.get(highLevelClient); + if (node == null) { + logger.log(Level.WARNING, "got event for unknown client"); + return; + } + fireNodeConnected(node); + } + + /** + * {@inheritDoc} + */ + public void clientDisconnected(HighLevelClient highLevelClient, Throwable throwable) { + synchronized (syncObject) { + Node node = clientNodes.remove(highLevelClient); + if (node == null) { + logger.log(Level.WARNING, "got event for unknown client"); + return; + } + nodeClients.remove(node); + fireNodeDisconnected(node, throwable); + } + } + } -- 2.7.4