add SubscribedUSKUpdate
[jSite2.git] / src / net / pterodactylus / util / fcp / FcpConnection.java
index 6d4ca97..81b5c47 100644 (file)
@@ -26,14 +26,13 @@ import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
-import net.pterodactylus.util.fcp.message.CloseConnectionDuplicateClientName;
-import net.pterodactylus.util.fcp.message.EndListPeers;
-import net.pterodactylus.util.fcp.message.NodeHello;
-import net.pterodactylus.util.fcp.message.Peer;
-import net.pterodactylus.util.fcp.message.SSKKeypair;
 import net.pterodactylus.util.io.Closer;
+import net.pterodactylus.util.io.LimitedInputStream;
 
 /**
  * An FCP connection to a Freenet node.
@@ -67,6 +66,20 @@ public class FcpConnection {
        /** The connection handler. */
        private FcpConnectionHandler connectionHandler;
 
+       /** Incoming message statistics. */
+       private Map<String, Integer> incomingMessageStatistics = Collections.synchronizedMap(new HashMap<String, Integer>());
+
+       /**
+        * Creates a new FCP connection to the freenet node running on localhost,
+        * using the default port.
+        * 
+        * @throws UnknownHostException
+        *             if the hostname can not be resolved
+        */
+       public FcpConnection() throws UnknownHostException {
+               this(InetAddress.getLocalHost());
+       }
+
        /**
         * Creates a new FCP connection to the Freenet node running on the given
         * host, listening on the default port.
@@ -188,6 +201,7 @@ public class FcpConnection {
        /**
         * Notifies listeners that a “Peer” message was received.
         * 
+        * @see FcpListener#receivedPeer(FcpConnection, Peer)
         * @param peer
         *            The “Peer” message
         */
@@ -200,6 +214,7 @@ public class FcpConnection {
        /**
         * Notifies all listeners that an “EndListPeers” message was received.
         * 
+        * @see FcpListener#receivedEndListPeers(FcpConnection, EndListPeers)
         * @param endListPeers
         *            The “EndListPeers” message
         */
@@ -210,6 +225,318 @@ public class FcpConnection {
        }
 
        /**
+        * Notifies all listeners that a “PeerNote” message was received.
+        * 
+        * @see FcpListener#receivedPeerNote(FcpConnection, PeerNote)
+        * @param peerNote
+        */
+       private void fireReceivedPeerNote(PeerNote peerNote) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPeerNote(this, peerNote);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “EndListPeerNotes” message was received.
+        * 
+        * @see FcpListener#receivedEndListPeerNotes(FcpConnection,
+        *      EndListPeerNotes)
+        * @param endListPeerNotes
+        *            The “EndListPeerNotes” message
+        */
+       private void fireReceivedEndListPeerNotes(EndListPeerNotes endListPeerNotes) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedEndListPeerNotes(this, endListPeerNotes);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “PeerRemoved” message was received.
+        * 
+        * @see FcpListener#receivedPeerRemoved(FcpConnection, PeerRemoved)
+        * @param peerRemoved
+        *            The “PeerRemoved” message
+        */
+       private void fireReceivedPeerRemoved(PeerRemoved peerRemoved) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPeerRemoved(this, peerRemoved);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “NodeData” message was received.
+        * 
+        * @see FcpListener#receivedNodeData(FcpConnection, NodeData)
+        * @param nodeData
+        *            The “NodeData” message
+        */
+       private void fireReceivedNodeData(NodeData nodeData) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedNodeData(this, nodeData);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “TestDDAReply” message was received.
+        * 
+        * @see FcpListener#receivedTestDDAReply(FcpConnection, TestDDAReply)
+        * @param testDDAReply
+        *            The “TestDDAReply” message
+        */
+       private void fireReceivedTestDDAReply(TestDDAReply testDDAReply) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedTestDDAReply(this, testDDAReply);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “TestDDAComplete” message was received.
+        * 
+        * @see FcpListener#receivedTestDDAComplete(FcpConnection, TestDDAComplete)
+        * @param testDDAComplete
+        *            The “TestDDAComplete” message
+        */
+       private void fireReceivedTestDDAComplete(TestDDAComplete testDDAComplete) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedTestDDAComplete(this, testDDAComplete);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “PersistentGet” message was received.
+        * 
+        * @param persistentGet
+        *            The “PersistentGet” message
+        */
+       private void fireReceivedPersistentGet(PersistentGet persistentGet) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPersistentGet(this, persistentGet);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “PersistentPut” message was received.
+        * 
+        * @see FcpListener#receivedPersistentPut(FcpConnection, PersistentPut)
+        * @param persistentPut
+        *            The “PersistentPut” message
+        */
+       private void fireReceivedPersistentPut(PersistentPut persistentPut) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPersistentPut(this, persistentPut);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “EndListPersistentRequests” message was
+        * received.
+        * 
+        * @param endListPersistentRequests
+        *            The “EndListPersistentRequests” message
+        */
+       private void fireReceivedEndListPersistentRequests(EndListPersistentRequests endListPersistentRequests) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedEndListPersistentRequests(this, endListPersistentRequests);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “URIGenerated” message was received.
+        * 
+        * @param uriGenerated
+        *            The “URIGenerated” message
+        */
+       private void fireReceivedURIGenerated(URIGenerated uriGenerated) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedURIGenerated(this, uriGenerated);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “DataFound” message was received.
+        * 
+        * @param dataFound
+        *            The “DataFound” message
+        */
+       private void fireReceivedDataFound(DataFound dataFound) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedDataFound(this, dataFound);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “AllData” message was received.
+        * 
+        * @param allData
+        *            The “AllData” message
+        */
+       private void fireReceivedAllData(AllData allData) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedAllData(this, allData);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “SimpleProgress” message was received.
+        * 
+        * @param simpleProgress
+        *            The “SimpleProgress” message
+        */
+       private void fireReceivedSimpleProgress(SimpleProgress simpleProgress) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedSimpleProgress(this, simpleProgress);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “StartedCompression” message was received.
+        * 
+        * @param startedCompression
+        *            The “StartedCompression” message
+        */
+       private void fireReceivedStartedCompression(StartedCompression startedCompression) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedStartedCompression(this, startedCompression);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “FinishedCompression” message was received.
+        * 
+        * @param finishedCompression
+        *            The “FinishedCompression” message
+        */
+       private void fireReceivedFinishedCompression(FinishedCompression finishedCompression) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receviedFinishedCompression(this, finishedCompression);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “UnknownPeerNoteType” message was
+        * received.
+        * 
+        * @param unknownPeerNoteType
+        *            The “UnknownPeerNoteType” message
+        */
+       private void fireReceivedUnknownPeerNoteType(UnknownPeerNoteType unknownPeerNoteType) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedUnknownPeerNoteType(this, unknownPeerNoteType);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “UnknownNodeIdentifier” message was
+        * received.
+        * 
+        * @param unknownNodeIdentifier
+        *            The “UnknownNodeIdentifier” message
+        */
+       private void fireReceivedUnknownNodeIdentifier(UnknownNodeIdentifier unknownNodeIdentifier) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedUnknownNodeIdentifier(this, unknownNodeIdentifier);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “ConfigData” message was received.
+        * 
+        * @param configData
+        *            The “ConfigData” message
+        */
+       private void fireReceivedConfigData(ConfigData configData) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedConfigData(this, configData);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “GetFailed” message was received.
+        * 
+        * @param getFailed
+        *            The “GetFailed” message
+        */
+       private void fireReceivedGetFailed(GetFailed getFailed) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedGetFailed(this, getFailed);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “PutFailed” message was received.
+        * 
+        * @param putFailed
+        *            The “PutFailed” message
+        */
+       private void fireReceivedPutFailed(PutFailed putFailed) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPutFailed(this, putFailed);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “IdentifierCollision” message was
+        * received.
+        * 
+        * @param identifierCollision
+        *            The “IdentifierCollision” message
+        */
+       private void fireReceivedIdentifierCollision(IdentifierCollision identifierCollision) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedIdentifierCollision(this, identifierCollision);
+               }
+       }
+
+       /**
+        * Notifies all listeners that an “PersistentPutDir” message was received.
+        * 
+        * @param persistentPutDir
+        *            The “PersistentPutDir” message
+        */
+       private void fireReceivedPersistentPutDir(PersistentPutDir persistentPutDir) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPersistentPutDir(this, persistentPutDir);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “PersistentRequestRemoved” message was
+        * received.
+        * 
+        * @param persistentRequestRemoved
+        *            The “PersistentRequestRemoved” message
+        */
+       private void fireReceivedPersistentRequestRemoved(PersistentRequestRemoved persistentRequestRemoved) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPersistentRequestRemoved(this, persistentRequestRemoved);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “SubscribedUSKUpdate” message was received.
+        * 
+        * @param subscribedUSKUpdate
+        *            The “SubscribedUSKUpdate” message
+        */
+       private void fireReceivedSubscribedUSKUpdate(SubscribedUSKUpdate subscribedUSKUpdate) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedSubscribedUSKUpdate(this, subscribedUSKUpdate);
+               }
+       }
+
+       /**
+        * Notifies all listeners that a “ProtocolError” message was received.
+        * 
+        * @param protocolError
+        *            The “ProtocolError” message
+        */
+       private void fireReceivedProtocolError(ProtocolError protocolError) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedProtocolError(this, protocolError);
+               }
+       }
+
+       /**
         * Notifies all registered listeners that a message has been received.
         * 
         * @see FcpListener#receivedMessage(FcpConnection, FcpMessage)
@@ -283,12 +610,76 @@ public class FcpConnection {
         */
        void handleMessage(FcpMessage fcpMessage) {
                String messageName = fcpMessage.getName();
-               if ("Peer".equals(messageName)) {
+               countMessage(messageName);
+               if ("SimpleProgress".equals(messageName)) {
+                       fireReceivedSimpleProgress(new SimpleProgress(fcpMessage));
+               } else if ("ProtocolError".equals(messageName)) {
+                       fireReceivedProtocolError(new ProtocolError(fcpMessage));
+               } else if ("PersistentGet".equals(messageName)) {
+                       fireReceivedPersistentGet(new PersistentGet(fcpMessage));
+               } else if ("PersistentPut".equals(messageName)) {
+                       fireReceivedPersistentPut(new PersistentPut(fcpMessage));
+               } else if ("PersistentPutDir".equals(messageName)) {
+                       fireReceivedPersistentPutDir(new PersistentPutDir(fcpMessage));
+               } else if ("URIGenerated".equals(messageName)) {
+                       fireReceivedURIGenerated(new URIGenerated(fcpMessage));
+               } else if ("EndListPersistentRequests".equals(messageName)) {
+                       fireReceivedEndListPersistentRequests(new EndListPersistentRequests(fcpMessage));
+               } else if ("Peer".equals(messageName)) {
                        fireReceivedPeer(new Peer(fcpMessage));
+               } else if ("PeerNote".equals(messageName)) {
+                       fireReceivedPeerNote(new PeerNote(fcpMessage));
+               } else if ("StartedCompression".equals(messageName)) {
+                       fireReceivedStartedCompression(new StartedCompression(fcpMessage));
+               } else if ("FinishedCompression".equals(messageName)) {
+                       fireReceivedFinishedCompression(new FinishedCompression(fcpMessage));
+               } else if ("GetFailed".equals(messageName)) {
+                       fireReceivedGetFailed(new GetFailed(fcpMessage));
+               } else if ("PutFailed".equals(messageName)) {
+                       fireReceivedPutFailed(new PutFailed(fcpMessage));
+               } else if ("DataFound".equals(messageName)) {
+                       fireReceivedDataFound(new DataFound(fcpMessage));
+               } else if ("SubscribedUSKUpdate".equals(messageName)) {
+                       fireReceivedSubscribedUSKUpdate(new SubscribedUSKUpdate(fcpMessage));
+               } else if ("IdentifierCollision".equals(messageName)) {
+                       fireReceivedIdentifierCollision(new IdentifierCollision(fcpMessage));
+               } else if ("AllData".equals(messageName)) {
+                       long dataLength;
+                       try {
+                               dataLength = Long.valueOf(fcpMessage.getField("DataLength"));
+                       } catch (NumberFormatException nfe1) {
+                               dataLength = -1;
+                       }
+                       LimitedInputStream payloadInputStream = new LimitedInputStream(remoteInputStream, dataLength);
+                       fireReceivedAllData(new AllData(fcpMessage, payloadInputStream));
+                       try {
+                               payloadInputStream.consume();
+                       } catch (IOException ioe1) {
+                               /* FIXME - what now? */
+                               /* well, ignore. when the connection handler fails, all fails. */
+                       }
+               } else if ("EndListPeerNotes".equals(messageName)) {
+                       fireReceivedEndListPeerNotes(new EndListPeerNotes(fcpMessage));
                } else if ("EndListPeers".equals(messageName)) {
                        fireReceivedEndListPeers(new EndListPeers(fcpMessage));
                } else if ("SSKKeypair".equals(messageName)) {
                        fireReceivedSSKKeypair(new SSKKeypair(fcpMessage));
+               } else if ("PeerRemoved".equals(messageName)) {
+                       fireReceivedPeerRemoved(new PeerRemoved(fcpMessage));
+               } else if ("PersistentRequestRemoved".equals(messageName)) {
+                       fireReceivedPersistentRequestRemoved(new PersistentRequestRemoved(fcpMessage));
+               } else if ("UnknownPeerNoteType".equals(messageName)) {
+                       fireReceivedUnknownPeerNoteType(new UnknownPeerNoteType(fcpMessage));
+               } else if ("UnknownNodeIdentifier".equals(messageName)) {
+                       fireReceivedUnknownNodeIdentifier(new UnknownNodeIdentifier(fcpMessage));
+               } else if ("NodeData".equals(messageName)) {
+                       fireReceivedNodeData(new NodeData(fcpMessage));
+               } else if ("TestDDAReply".equals(messageName)) {
+                       fireReceivedTestDDAReply(new TestDDAReply(fcpMessage));
+               } else if ("TestDDAComplete".equals(messageName)) {
+                       fireReceivedTestDDAComplete(new TestDDAComplete(fcpMessage));
+               } else if ("ConfigData".equals(messageName)) {
+                       fireReceivedConfigData(new ConfigData(fcpMessage));
                } else if ("NodeHello".equals(messageName)) {
                        fireReceivedNodeHello(new NodeHello(fcpMessage));
                } else if ("CloseConnectionDuplicateClientName".equals(messageName)) {
@@ -298,4 +689,33 @@ public class FcpConnection {
                }
        }
 
+       /**
+        * Handles a disconnect from the node.
+        */
+       synchronized void handleDisconnect() {
+               Closer.close(remoteInputStream);
+               Closer.close(remoteOutputStream);
+               Closer.close(remoteSocket);
+               connectionHandler = null;
+       }
+
+       //
+       // PRIVATE METHODS
+       //
+
+       /**
+        * Incremets the counter in {@link #incomingMessageStatistics} by <cod>1</code>
+        * for the given message name.
+        * 
+        * @param name
+        *            The name of the message to count
+        */
+       private void countMessage(String name) {
+               int oldValue = 0;
+               if (incomingMessageStatistics.containsKey(name)) {
+                       oldValue = incomingMessageStatistics.get(name);
+               }
+               incomingMessageStatistics.put(name, oldValue + 1);
+       }
+
 }