make connections work
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 14 May 2008 06:50:54 +0000 (06:50 +0000)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 14 May 2008 06:50:54 +0000 (06:50 +0000)
git-svn-id: http://trooper/svn/projects/jSite/trunk@871 c3eda9e8-030b-0410-8277-bc7414b0a119

src/net/pterodactylus/jsite/core/Core.java
src/net/pterodactylus/jsite/core/CoreImpl.java
src/net/pterodactylus/jsite/core/CoreListener.java
src/net/pterodactylus/jsite/core/Node.java
src/net/pterodactylus/jsite/core/NodeListener.java
src/net/pterodactylus/jsite/core/NodeManager.java
src/net/pterodactylus/jsite/core/RequestManager.java
src/net/pterodactylus/jsite/gui/ManageNodesDialog.java
src/net/pterodactylus/jsite/gui/SwingInterface.java
src/net/pterodactylus/jsite/i18n/jSite.properties
src/net/pterodactylus/jsite/i18n/jSite_de.properties

index f04bb40..38e8914 100644 (file)
@@ -51,10 +51,12 @@ public interface Core {
         * 
         * @param node
         *            The node to add
+        * @return <code>true</code> if the node was added, <code>false</code>
+        *         if it was not added because it was already known
         * @throws UnknownHostException
         *             if the hostname of the node can not be resolved
         */
-       public void addNode(Node node) throws UnknownHostException;
+       public boolean addNode(Node node) throws UnknownHostException;
 
        /**
         * Removes the given node from the core.
index 682199e..07c6345 100644 (file)
@@ -237,6 +237,20 @@ public class CoreImpl implements Core, NodeListener, RequestListener {
        }
 
        /**
+        * Notifies all listeners that a connection to a node has failed.
+        * 
+        * @param node
+        *            The node that could not be connected
+        * @param cause
+        *            The cause of the failure
+        */
+       private void fireNodeConnectionFailed(Node node, Throwable cause) {
+               for (CoreListener coreListener: coreListeners) {
+                       coreListener.nodeConnectionFailed(node, cause);
+               }
+       }
+
+       /**
         * Notifies all listeners that the given node was disconnected.
         * 
         * @param node
@@ -403,9 +417,8 @@ public class CoreImpl implements Core, NodeListener, RequestListener {
        /**
         * {@inheritDoc}
         */
-       public void addNode(Node node) throws UnknownHostException {
-               nodeManager.addNode(node);
-               fireNodeAdded(node);
+       public boolean addNode(Node node) throws UnknownHostException {
+               return nodeManager.addNode(node);
        }
 
        /**
@@ -413,7 +426,6 @@ public class CoreImpl implements Core, NodeListener, RequestListener {
         */
        public void removeNode(Node node) {
                nodeManager.removeNode(node);
-               fireNodeRemoved(node);
        }
 
        /**
@@ -479,6 +491,13 @@ public class CoreImpl implements Core, NodeListener, RequestListener {
        /**
         * {@inheritDoc}
         */
+       public void nodeConnectionFailed(Node node, Throwable cause) {
+               fireNodeConnectionFailed(node, cause);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
        public void nodeDisconnected(Node node, Throwable throwable) {
                fireNodeDisconnected(node, throwable);
        }
@@ -500,6 +519,6 @@ public class CoreImpl implements Core, NodeListener, RequestListener {
         *      boolean)
         */
        public void requestProgressed(Node node, Request request, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
-       fireRequestProgressed(node, request, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal);
-    }
+               fireRequestProgressed(node, request, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal);
+       }
 }
index fb109d7..04b063e 100644 (file)
@@ -163,6 +163,16 @@ public interface CoreListener {
        public void nodeConnected(Node node);
 
        /**
+        * Notifies a listener that a connection to a node has failed.
+        * 
+        * @param node
+        *            The node that could not be connected
+        * @param cause
+        *            The cause of the failure
+        */
+       public void nodeConnectionFailed(Node node, Throwable cause);
+
+       /**
         * Notifies all listeners that the core disconnected from the given node.
         * 
         * @param node
index b3a98e9..afcce6a 100644 (file)
 
 package net.pterodactylus.jsite.core;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * Container for a Freenet node.
- *
+ * 
  * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
  * @version $Id$
  */
 public class Node {
 
+       /** Property change listeners. */
+       private final List<PropertyChangeListener> propertyChangeListeners = Collections.synchronizedList(new ArrayList<PropertyChangeListener>());
+
        /** The name of the node. */
        private String name;
 
@@ -36,9 +45,55 @@ public class Node {
        /** The port number of the node. */
        private int port;
 
+       //
+       // EVENT MANAGEMENT
+       //
+
+       /**
+        * Adds a property change listener.
+        * 
+        * @param propertyChangeListener
+        *            The property change listener to add
+        */
+       public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
+               propertyChangeListeners.add(propertyChangeListener);
+       }
+
+       /**
+        * Removes a property change listener.
+        * 
+        * @param propertyChangeListener
+        *            The property change listener to remove
+        */
+       public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) {
+               propertyChangeListeners.remove(propertyChangeListener);
+       }
+
+       /**
+        * Notifies all listeners that a property has changed.
+        * 
+        * @param property
+        *            The name of the property
+        * @param oldValue
+        *            The old value of the property
+        * @param newValue
+        *            The new value of the property
+        */
+       private void firePropertyChange(String property, Object oldValue, Object newValue) {
+               PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(this, property, oldValue, newValue);
+               for (PropertyChangeListener propertyChangeListener: propertyChangeListeners) {
+                       propertyChangeListener.propertyChange(propertyChangeEvent);
+               }
+
+       }
+
+       //
+       // ACCESSORS
+       //
+
        /**
         * Returns the user-given name of the node.
-        *
+        * 
         * @return The name of the node
         */
        public String getName() {
@@ -47,17 +102,21 @@ public class Node {
 
        /**
         * Sets the user-given name of the node.
-        *
+        * 
         * @param name
         *            The name of the node
         */
        public void setName(String name) {
+               String oldName = this.name;
                this.name = name;
+               if (((oldName != null) && (name == null)) || ((oldName == null) && (name != null)) || ((name != null) && !name.equals(oldName))) {
+                       firePropertyChange("name", oldName, name);
+               }
        }
 
        /**
         * Returns the hostname of the node.
-        *
+        * 
         * @return The hostname of the node
         */
        public String getHostname() {
@@ -66,17 +125,21 @@ public class Node {
 
        /**
         * Sets the hostname of the node.
-        *
+        * 
         * @param hostname
         *            The hostname of the node
         */
        public void setHostname(String hostname) {
+               String oldHostname = this.hostname;
                this.hostname = hostname;
+               if (((oldHostname != null) && (hostname == null)) || ((oldHostname == null) && (hostname != null)) || ((hostname != null) && !hostname.equals(oldHostname))) {
+                       firePropertyChange("hostname", oldHostname, hostname);
+               }
        }
 
        /**
         * Returns the port number of the node.
-        *
+        * 
         * @return The port number of the node
         */
        public int getPort() {
@@ -85,27 +148,39 @@ public class Node {
 
        /**
         * Sets the port number of the node.
-        *
+        * 
         * @param port
         *            The port number of the node
         */
        public void setPort(int port) {
+               int oldPort = this.port;
                this.port = port;
-       }
-
-       /**
-        * {@inheritDoc} Two Node objects are considered equal if their hostnames
-        * and their port numbers are equal.
-        */
-       @Override
-       public boolean equals(Object object) {
-               if ((object == null) || !(object instanceof Node)) {
-                       return false;
+               if (oldPort != port) {
+                       firePropertyChange("port", oldPort, port);
                }
-               Node node = (Node) object;
-               return hostname.equals(node.hostname) && port == node.port;
        }
 
+//     /**
+//      * {@inheritDoc} Two Node objects are considered equal if their hostnames
+//      * and their port numbers are equal.
+//      */
+//     @Override
+//     public boolean equals(Object object) {
+//             if ((object == null) || !(object instanceof Node)) {
+//                     return false;
+//             }
+//             Node node = (Node) object;
+//             return hostname.equals(node.hostname) && port == node.port;
+//     }
+
+//     /**
+//      * {@inheritDoc}
+//      */
+//     @Override
+//     public int hashCode() {
+//             return hostname.hashCode() ^ (-1 - port);
+//     }
+       
        /**
         * {@inheritDoc}
         */
index 95254c1..615fbbe 100644 (file)
@@ -54,8 +54,21 @@ public interface NodeListener extends EventListener {
        public void nodeConnected(Node node);
 
        /**
-        * Notifies a listener that a connection to the given node was severed. The
-        * listener is responsible for
+        * Notifies a listener that a connection to a node has failed.
+        * 
+        * @param node
+        *            The node that could not be connected
+        * @param cause
+        *            The cause of the failure
+        */
+       public void nodeConnectionFailed(Node node, Throwable cause);
+
+       /**
+        * Notifies a listener that a connection to the given node was severed. If
+        * the listener needs the high-level client associated with the node for
+        * anything else (like deregistering as listener from it) it should retrieve
+        * the high-level client using {@link NodeManager#getHighLevelClient(Node)}
+        * before this method returns!
         * 
         * @param node
         *            The node that is now disconnected
index 971d5c5..c676289 100644 (file)
@@ -19,6 +19,8 @@
 
 package net.pterodactylus.jsite.core;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -29,12 +31,10 @@ 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;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -49,7 +49,7 @@ import net.pterodactylus.util.logging.Logging;
  * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
  * @version $Id$
  */
-public class NodeManager implements Iterable<Node>, HighLevelClientListener {
+public class NodeManager implements Iterable<Node>, PropertyChangeListener, HighLevelClientListener {
 
        /** Logger. */
        private static final Logger logger = Logging.getLogger(NodeManager.class.getName());
@@ -72,9 +72,6 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
        /** All FCP connections. */
        private Map<Node, HighLevelClient> nodeClients = Collections.synchronizedMap(new HashMap<Node, HighLevelClient>());
 
-       /** Keeps track of which connection is in use right now. */
-       private Set<HighLevelClient> usedConnections = Collections.synchronizedSet(new HashSet<HighLevelClient>());
-
        /** Maps nodes to high-level clients. */
        private Map<HighLevelClient, Node> clientNodes = Collections.synchronizedMap(new HashMap<HighLevelClient, Node>());
 
@@ -152,6 +149,20 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
        }
 
        /**
+        * Notifies all listeners that a connection to a node has failed.
+        * 
+        * @param node
+        *            The node that could not be connected
+        * @param cause
+        *            The cause of the failure
+        */
+       private void fireNodeConnectionFailed(Node node, Throwable cause) {
+               for (NodeListener nodeListener: nodeListeners) {
+                       nodeListener.nodeConnectionFailed(node, cause);
+               }
+       }
+
+       /**
         * Notifies all listeners that the given node was disconnected.
         * 
         * @param node
@@ -258,7 +269,7 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
                logger.fine("loaded " + loadedNodes.size() + " nodes from config");
                synchronized (syncObject) {
                        nodes.clear();
-                       for (Node node: nodes) {
+                       for (Node node: loadedNodes) {
                                addNode(node);
                        }
                }
@@ -301,20 +312,22 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
         * @see #connect(Node)
         * @param node
         *            The node to connect to
-        * @throws UnknownHostException
-        *             if the hostname of the node can not be resolved
+        * @return <code>true</code> if the node was added, <code>false</code>
+        *         if the node was not added because it was already known
         */
-       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);
-                       }
+       public boolean addNode(Node node) {
+               if (nodes.contains(node)) {
+                       logger.warning("was told to add already known node: " + node);
+                       return false;
                }
+               node.addPropertyChangeListener(this);
+               HighLevelClient highLevelClient = new HighLevelClient(clientName);
+               nodes.add(node);
+               clientNodes.put(highLevelClient, node);
+               nodeClients.put(node, highLevelClient);
+               highLevelClient.addHighLevelClientListener(this);
+               fireNodeAdded(node);
+               return true;
        }
 
        /**
@@ -332,6 +345,7 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
                        if (nodeClients.containsKey(node)) {
                                disconnect(node);
                        }
+                       node.removePropertyChangeListener(this);
                        fireNodeRemoved(node);
                }
        }
@@ -344,13 +358,17 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
         */
        public void connect(Node node) {
                HighLevelClient highLevelClient;
-               synchronized (syncObject) {
-                       highLevelClient = nodeClients.get(node);
+               highLevelClient = nodeClients.get(node);
+               if (highLevelClient == null) {
+                       logger.warning("was told to connect to unknown node: " + node);
+                       return;
                }
                try {
-                       highLevelClient.connect();
+                       highLevelClient.connect(node.getHostname(), node.getPort());
+               } catch (UnknownHostException uhe1) {
+                       fireNodeConnectionFailed(node, uhe1);
                } catch (IOException ioe1) {
-                       fireNodeDisconnected(node, ioe1);
+                       fireNodeConnectionFailed(node, ioe1);
                }
        }
 
@@ -380,103 +398,21 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
        }
 
        /**
-        * “Borrows” a high-level client for the given node. A borrowed client
-        * <strong>has</strong> 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.
+        * Returns the high-level client for a given node.
         * 
         * @param node
         *            The node to get a high-level client for
         * @return The high-level client for a node, or <code>null</code> 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();
-               }
+       public HighLevelClient getHighLevelClient(Node node) {
+               return nodeClients.get(node);
        }
 
        //
        // PRIVATE METHODS
        //
 
-       /**
-        * Finds a currently unused high-level client, optionally waiting until a
-        * client is free and marking it used.
-        * 
-        * @param wait
-        *            <code>true</code> to wait for a free connection,
-        *            <code>false</code> to return <code>null</code>
-        * @param markAsUsed
-        *            <code>true</code> to mark the connection as used before
-        *            returning it, <code>false</code> not to mark it
-        * @return An unused FCP connection, or <code>null</code> if no connection
-        *         could be found
-        */
-       @SuppressWarnings("unused")
-       private HighLevelClient findUnusedClient(boolean wait, boolean markAsUsed) {
-               synchronized (syncObject) {
-                       HighLevelClient freeHighLevelClient = null;
-                       while (freeHighLevelClient == null) {
-                               for (HighLevelClient highLevelClient: nodeClients.values()) {
-                                       if (!usedConnections.contains(highLevelClient)) {
-                                               freeHighLevelClient = highLevelClient;
-                                               break;
-                                       }
-                               }
-                               if (freeHighLevelClient != null) {
-                                       if (markAsUsed) {
-                                               usedConnections.add(freeHighLevelClient);
-                                       }
-                                       return freeHighLevelClient;
-                               }
-                               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;
-               }
-       }
-
        //
        // INTERFACE HighLevelClientListener
        //
@@ -500,15 +436,45 @@ public class NodeManager implements Iterable<Node>, HighLevelClientListener {
        public void clientDisconnected(HighLevelClient highLevelClient, Throwable throwable) {
                logger.log(Level.FINER, "clientDisconnected(c=" + highLevelClient + ",t=" + throwable + ")");
                synchronized (syncObject) {
-                       Node node = clientNodes.remove(highLevelClient);
+                       Node node = clientNodes.get(highLevelClient);
                        if (node == null) {
                                logger.log(Level.WARNING, "got event for unknown client");
                                return;
                        }
-                       nodeClients.remove(node);
-                       usedConnections.remove(highLevelClient);
                        fireNodeDisconnected(node, throwable);
                }
        }
 
+       //
+       // INTERFACE PropertyChangeListener
+       //
+
+       /**
+        * {@inheritDoc}
+        */
+       public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
+               Object eventSource = propertyChangeEvent.getSource();
+               if (eventSource instanceof Node) {
+                       String propertyName = propertyChangeEvent.getPropertyName();
+                       if ("hostname".equals(propertyName) || "port".equals(propertyName)) {
+                               Node node = (Node) eventSource;
+                               HighLevelClient highLevelClient = nodeClients.get(node);
+                               if (highLevelClient == null) {
+                                       logger.log(Level.WARNING, "got property change event for unknown node: " + node);
+                                       return;
+                               }
+                               if (highLevelClient.isConnected()) {
+                                       highLevelClient.disconnect();
+                                       try {
+                                               highLevelClient.connect(node.getHostname(), node.getPort());
+                                       } catch (UnknownHostException uhe1) {
+                                               fireNodeConnectionFailed(node, uhe1);
+                                       } catch (IOException ioe1) {
+                                               fireNodeConnectionFailed(node, ioe1);
+                                       }
+                               }
+                       }
+               }
+       }
+
 }
index b312d43..002cd17 100644 (file)
@@ -159,34 +159,30 @@ public class RequestManager implements NodeListener, HighLevelProgressListener {
         *             if an I/O error occurs while communicating with the node
         */
        private void getRequests(final Node node) throws IOException {
-               HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(node);
+               HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
                if (highLevelClient == null) {
                        logger.log(Level.WARNING, "no client for node: " + node);
                        return;
                }
-               try {
-                       HighLevelCallback<RequestListResult> requestListCallback = highLevelClient.getRequests();
-                       requestListCallback.addHighLevelCallbackListener(new HighLevelCallbackListener<RequestListResult>() {
+               HighLevelCallback<RequestListResult> requestListCallback = highLevelClient.getRequests();
+               requestListCallback.addHighLevelCallbackListener(new HighLevelCallbackListener<RequestListResult>() {
 
-                               @SuppressWarnings("synthetic-access")
-                               public void gotResult(HighLevelCallback<RequestListResult> highLevelCallback) {
-                                       RequestListResult requestListResult;
-                                       try {
-                                               requestListResult = highLevelCallback.getResult();
-                                       } catch (InterruptedException e) {
-                                               logger.log(Level.SEVERE, "getResult() blocked and was interrupted");
-                                               return;
-                                       }
-                                       for (RequestResult requestResult: requestListResult) {
-                                               Request request = new Request(requestResult.getIdentifier());
-                                               /* TODO - fill request */
-                                               fireRequestAdded(node, request);
-                                       }
+                       @SuppressWarnings("synthetic-access")
+                       public void gotResult(HighLevelCallback<RequestListResult> highLevelCallback) {
+                               RequestListResult requestListResult;
+                               try {
+                                       requestListResult = highLevelCallback.getResult();
+                               } catch (InterruptedException e) {
+                                       logger.log(Level.SEVERE, "getResult() blocked and was interrupted");
+                                       return;
                                }
-                       });
-               } finally {
-                       nodeManager.returnHighLevelClient(highLevelClient);
-               }
+                               for (RequestResult requestResult: requestListResult) {
+                                       Request request = new Request(requestResult.getIdentifier());
+                                       /* TODO - fill request */
+                                       fireRequestAdded(node, request);
+                               }
+                       }
+               });
        }
 
        //
@@ -197,41 +193,37 @@ public class RequestManager implements NodeListener, HighLevelProgressListener {
         * {@inheritDoc}
         */
        public void nodeAdded(Node node) {
-               HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(node);
+               HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
                if (highLevelClient == null) {
+                       logger.warning("got nodeAdded but no high-level client: " + node);
                        return;
                }
-               try {
-                       highLevelClient.addHighLevelProgressListener(this);
-               } finally {
-                       nodeManager.returnHighLevelClient(highLevelClient);
-               }
+               highLevelClient.addHighLevelProgressListener(this);
        }
 
        /**
         * {@inheritDoc}
         */
        public void nodeRemoved(Node node) {
-               /* ignore. */
+               HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
+               if (highLevelClient == null) {
+                       logger.warning("got nodeRemoved but no high-level client: " + node);
+                       return;
+               }
+               highLevelClient.removeHighLevelProgressListener(this);
        }
 
        /**
         * {@inheritDoc}
         */
        public void nodeConnected(Node node) {
-               HighLevelClient highLevelClient = nodeManager.borrowHighLevelClient(node);
+               HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
                if (highLevelClient == null) {
                        logger.log(Level.WARNING, "got no high-level client for node " + node);
                        return;
                }
                try {
                        highLevelClient.setWatchGlobal(true);
-               } catch (IOException ioe1) {
-                       /* ignore exception, disconnects are handled elsewhere. */
-               } finally {
-                       nodeManager.returnHighLevelClient(highLevelClient);
-               }
-               try {
                        getRequests(node);
                } catch (IOException e) {
                        /* ignore exception, disconnects are handled elsewhere. */
@@ -241,8 +233,19 @@ public class RequestManager implements NodeListener, HighLevelProgressListener {
        /**
         * {@inheritDoc}
         */
+       public void nodeConnectionFailed(Node node, Throwable cause) {
+               /* we don't care about this. */
+       }
+
+       /**
+        * {@inheritDoc}
+        */
        public void nodeDisconnected(Node node, Throwable throwable) {
-               /* TODO - remove all requests. */
+               HighLevelClient highLevelClient = nodeManager.getHighLevelClient(node);
+               if (highLevelClient == null) {
+                       logger.warning("got nodeDisconnected from node without high-level client: " + node);
+                       return;
+               }
        }
 
        //
index cf32cae..0598144 100644 (file)
@@ -22,10 +22,12 @@ package net.pterodactylus.jsite.gui;
 import java.awt.BorderLayout;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.logging.Logger;
 
 import javax.swing.AbstractListModel;
 import javax.swing.BorderFactory;
@@ -46,6 +48,7 @@ import net.pterodactylus.jsite.i18n.I18nable;
 import net.pterodactylus.jsite.i18n.gui.I18nAction;
 import net.pterodactylus.jsite.i18n.gui.I18nLabel;
 import net.pterodactylus.jsite.main.Version;
+import net.pterodactylus.util.logging.Logging;
 import net.pterodactylus.util.swing.SwingUtils;
 
 /**
@@ -56,6 +59,10 @@ import net.pterodactylus.util.swing.SwingUtils;
  */
 public class ManageNodesDialog extends JDialog implements ListSelectionListener, I18nable {
 
+       /** The logger.  */
+       @SuppressWarnings("unused")
+       private static final Logger logger = Logging.getLogger(ManageNodesDialog.class.getName());
+
        /** The core. */
        private final Core core;
 
@@ -265,7 +272,17 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener,
                        newNode.setName(editNodeDialog.getNodeName());
                        newNode.setHostname(editNodeDialog.getNodeHostname());
                        newNode.setPort(editNodeDialog.getNodePort());
-                       nodeListModel.addNode(newNode);
+                       try {
+                               if (!core.addNode(newNode)) {
+                                       JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeAlreadyKnown.message", newNode.getHostname(), newNode.getPort()), I18n.get("manageNodesDialog.error.nodeAlreadyKnown.title"), JOptionPane.ERROR_MESSAGE);
+                               }
+                       } catch (UnknownHostException e) {
+                               /*
+                                * normally this shouldn't throw because the node editor catches
+                                * it.
+                                */
+                               JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeUnresolvable.message", newNode.getHostname()), I18n.get("manageNodesDialog.error.nodeUnresolvable.title"), JOptionPane.ERROR_MESSAGE);
+                       }
                }
        }
 
@@ -374,7 +391,7 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener,
        }
 
        /**
-        * List model for the {@link ManageNodesDialog#nodeList}. TODO
+        * List model for the {@link ManageNodesDialog#nodeList}.
         * 
         * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
         * @version $Id$
index bb0bb9e..0a945db 100644 (file)
@@ -217,6 +217,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
                if ((mainWindowX != -1) && (mainWindowY != -1) && (mainWindowWidth != -1) && (mainWindowHeight != -1)) {
                        mainWindow.setLocation(mainWindowX, mainWindowY);
                        mainWindow.setSize(mainWindowWidth, mainWindowHeight);
+                       mainWindow.validate();
                }
                logWindow = new LogWindow();
        }
@@ -681,7 +682,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
                nodeNodeDisconnectActions.clear();
                nodeDisconnectActionNodes.clear();
                for (Node node: nodes) {
-                       logger.finer("adding node “" + node + "” to menu");
+                       logger.finer("adding node “" + node + "” to menus");
                        Action nodeConnectAction = new AbstractAction(node.getName()) {
 
                                /**
@@ -904,6 +905,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
        public void nodeAdded(Node node) {
                logger.log(Level.INFO, "node added: " + node);
                nodeList.add(node);
+               logger.log(Level.FINE, "nodeList.size(): " + nodeList.size());
                manageNodesDialog.setNodeList(nodeList);
                rebuildNodeActions(nodeList);
                mainWindow.refreshNodeMenuItems();
@@ -942,6 +944,17 @@ public class SwingInterface implements CoreListener, LoggingListener {
        /**
         * {@inheritDoc}
         */
+       public void nodeConnectionFailed(Node node, Throwable cause) {
+               Action nodeConnectAction = nodeNodeConnectActions.get(node);
+               nodeConnectActions.add(nodeConnectAction);
+               mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectionToNodeFailed", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given"));
+               JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.nodeConnectionFailed.message", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given"), I18n.get("mainWindow.error.nodeConnectionFailed.title"), JOptionPane.ERROR_MESSAGE);
+               mainWindow.refreshNodeMenuItems();
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
        public void nodeDisconnected(Node node, Throwable throwable) {
                Action nodeConnectAction = nodeNodeConnectActions.get(node);
                nodeConnectActions.add(nodeConnectAction);
@@ -964,7 +977,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
         */
        public void requestProgressed(Request request, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
                /* TODO - update table model */
-               mainWindow.setStatusBarText(request.getIdentifier() + " @ " + ((10000 * successfulBlocks / requiredBlocks) / 100.0));
+               mainWindow.setStatusBarText(request.getIdentifier() + " @ " + ((10000 * successfulBlocks / requiredBlocks) / 100.0) + "%");
        }
 
        //
index 1985633..0a3ba80 100644 (file)
@@ -42,15 +42,19 @@ mainWindow.warning.multipleNodesNotAdvancedMode.message: <html>You have enabled
 mainWindow.error.projectLoadingFailed.title: Loading Projects Failed
 mainWindow.error.projectLoadingFailed.message: Loading the projects from \u201c{0}\u201d has failed.
 
+mainWindow.error.nodeConnectionFailed.title: Connecting to Node Failed
+mainWindow.error.nodeConnectionFailed.message: Connecting to node \u201c{0}\u201d (at {1}:{2,number,#}) has failed: {3}
+
 mainWindow.statusBar.coreLoaded: Core loaded.
 mainWindow.statusBar.coreStopped: Core stopped.
 mainWindow.statusBar.projectLoadingDone: Projects loaded.
 mainWindow.statusBar.projectSavingDone: Projects saved.
 mainWindow.statusBar.loadingNodesDone: Nodes loaded.
 mainWindow.statusBar.savingNodesDone: Nodes saved.
-mainWindow.statusBar.connectingToNode: Connecting to \u201c{0}\u201d (at {1}:{2})\u2026
-mainWindow.statusBar.connectedToNode: Connected to \u201c{0}\u201d (at {1}:{2}).
-mainWindow.statusBar.disconnectedFromNode: Connected to \u201c{0}\u201d (at {1}:{2}).
+mainWindow.statusBar.connectingToNode: Connecting to \u201c{0}\u201d (at {1}:{2,number,#})\u2026
+mainWindow.statusBar.connectedToNode: Connected to \u201c{0}\u201d (at {1}:{2,number,#}).
+mainWindow.statusBar.connectionToNodeFailed: Connection to \u201c{0}\u201d (at {1}:{2,number,#}) failed: {3}
+mainWindow.statusBar.disconnectedFromNode: Disconnected from \u201c{0}\u201d (at {1}:{2,number,#}).
 
 # main menus
 mainWindow.menu.jSite.name: jSite
@@ -186,6 +190,12 @@ manageNodesDialog.error.nodeListEmpty.message: The node list is empty.
 manageNodesDialog.error.nodeConnected.title: Node Is Connected
 manageNodesDialog.error.nodeConnected.message: The Node \u201c{0}\u201d is still connected. Do you really want to delete it?
 
+manageNodesDialog.error.nodeUnresolvable.title: Node hostname can not be resolved
+manageNodesDialog.error.nodeUnresolvable.message: The hostname of the node (\u201c{0}\u201d) can not be resolved.
+
+manageNodesDialog.error.nodeAlreadyKnown.title: Node Already Known
+manageNodesDialog.error.nodeAlreadyKnown.message: There already is a node with the hostname (\u201c{0}\u201d) and port ({1,number,#}).
+
 # the "edit node" dialog
 editNodeDialog.title: Edit Node
 
index 271ab48..fb7e450 100644 (file)
@@ -42,15 +42,19 @@ mainWindow.warning.multipleNodesNotAdvancedMode.message: <html>Der einfache Modu
 mainWindow.error.projectLoadingFailed.title: Laden der Projekte fehlgeschlagen
 mainWindow.error.projectLoadingFailed.message: Die Projekte aus \u201e{0}\u201c konnten nicht geladen werden.
 
+mainWindow.error.nodeConnectionFailed.title: Verbindung mit Node fehlgeschlagen
+mainWindow.error.nodeConnectionFailed.message: Die Verbindung zum Node \u201e{0}\u201c ({1}:{2,number,#}) konnte nicht hergestellt werden: {3}
+
 mainWindow.statusBar.coreLoaded: Kern geladen.
 mainWindow.statusBar.coreStopped: Kern angehalten.
 mainWindow.statusBar.projectLoadingDone: Projekte geladen.
 mainWindow.statusBar.projectSavingDone: Projekte gespeichert.
 mainWindow.statusBar.loadingNodesDone: Nodes geladen.
 mainWindow.statusBar.savingNodesDone: Nodes gespeichert.
-mainWindow.statusBar.connectingToNode: Verbindung zum Node \u201e{0}\u201c ({1}:{2}) wird hergestellt\u2026
-mainWindow.statusBar.connectedToNode: Verbindung zum Node \u201e{0}\u201c ({1}:{2}) hergestellt.
-mainWindow.statusBar.disconnectedFromNode: Verbindung von Node \u201e{0}\u201c ({1}:{2}) getrennt.
+mainWindow.statusBar.connectingToNode: Verbindung zum Node \u201e{0}\u201c ({1}:{2,number,#}) wird hergestellt\u2026
+mainWindow.statusBar.connectedToNode: Verbindung zum Node \u201e{0}\u201c ({1}:{2,number,#}) hergestellt.
+mainWindow.statusBar.connectionToNodeFailed: Verbindung zu Node \u201e{0}\u201c ({1}:{2,number,#}) fehlgeschlagen: {3}
+mainWindow.statusBar.disconnectedFromNode: Verbindung von Node \u201e{0}\u201c ({1}:{2,number,#}) getrennt.
 
 # main menus
 mainWindow.menu.jSite.name: jSite
@@ -186,6 +190,12 @@ manageNodesDialog.error.nodeListEmpty.message: Es wurden keine Nodes konfigurier
 manageNodesDialog.error.nodeConnected.title: Node ist verbunden
 manageNodesDialog.error.nodeConnected.message: Mit dem Node \u201e{0}\u201c besteht momentan eine Verbindung. Wollen Sie ihn wirklich l\u00f6schen?
 
+manageNodesDialog.error.nodeUnresolvable.title: Hostname des Nodes ung\u00fcltig
+manageNodesDialog.error.nodeUnresolvable.message: Der Hostname des Nodes (\u201e{0}\u201c) kann nicht aufgel\u00f6st werden.
+
+manageNodesDialog.error.nodeAlreadyKnown.title: Node schon bekannt
+manageNodesDialog.error.nodeAlreadyKnown.message: Es gibt bereits einen Node mit diesem Hostnamen (\u201e{0}\u201c) und Port ({1,number,#}).
+
 # the "edit node" dialog
 editNodeDialog.title: Edit Node