✨ Add String-based dispatcher implementation of FcpListener
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 2 Sep 2024 18:22:42 +0000 (20:22 +0200)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 2 Sep 2024 18:22:42 +0000 (20:22 +0200)
src/main/java/net/pterodactylus/fcp/DispatchingFcpAdapter.java [new file with mode: 0644]
src/test/java/net/pterodactylus/fcp/DispatchingFcpAdapterTest.java [new file with mode: 0644]

diff --git a/src/main/java/net/pterodactylus/fcp/DispatchingFcpAdapter.java b/src/main/java/net/pterodactylus/fcp/DispatchingFcpAdapter.java
new file mode 100644 (file)
index 0000000..e746316
--- /dev/null
@@ -0,0 +1,243 @@
+package net.pterodactylus.fcp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+/**
+ * {@link FcpListener} implementation that dispatches messages to event
+ * listeners that are really just {@link Consumer}s. All methods named
+ * “receivedX” from the {@link FcpListener} interface can be dispatched by
+ * calling {@link #addListener(String, Consumer)} with “X” as the message
+ * name. Registering a listener for the method
+ * {@link FcpListener#connectionClosed(FcpConnection, Throwable)} uses
+ * {@code "ConnectionClosed"} as message name, and the given consumer
+ * will receive the throwable.
+ */
+public class DispatchingFcpAdapter implements FcpListener {
+
+       public <T> void addListener(String message, Consumer<T> eventListener) {
+               eventListeners.merge(message, singletonList((Consumer<Object>) eventListener), (l1, l2) -> {
+                       List<Consumer<? super Object>> merged = new ArrayList<>(l1);
+                       merged.addAll(l2);
+                       return merged;
+               });
+       }
+
+       @Override
+       public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
+               dispatchEvent("NodeHello", nodeHello);
+       }
+
+       @Override
+       public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
+               dispatchEvent("CloseConnectionDuplicateClientName", closeConnectionDuplicateClientName);
+       }
+
+       @Override
+       public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
+               dispatchEvent("SSKKeypair", sskKeypair);
+       }
+
+       @Override
+       public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
+               dispatchEvent("Peer", peer);
+       }
+
+       @Override
+       public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
+               dispatchEvent("EndListPeers", endListPeers);
+       }
+
+       @Override
+       public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
+               dispatchEvent("PeerNote", peerNote);
+       }
+
+       @Override
+       public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
+               dispatchEvent("EndListPeerNotes", endListPeerNotes);
+       }
+
+       @Override
+       public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
+               dispatchEvent("PeerRemoved", peerRemoved);
+       }
+
+       @Override
+       public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
+               dispatchEvent("NodeData", nodeData);
+       }
+
+       @Override
+       public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
+               dispatchEvent("TestDDAReply", testDDAReply);
+       }
+
+       @Override
+       public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
+               dispatchEvent("TestDDAComplete", testDDAComplete);
+       }
+
+       @Override
+       public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
+               dispatchEvent("PersistentGet", persistentGet);
+       }
+
+       @Override
+       public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
+               dispatchEvent("PersistentPut", persistentPut);
+       }
+
+       @Override
+       public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
+               dispatchEvent("EndListPersistentRequests", endListPersistentRequests);
+       }
+
+       @Override
+       public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
+               dispatchEvent("URIGenerated", uriGenerated);
+       }
+
+       @Override
+       public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
+               dispatchEvent("DataFound", dataFound);
+       }
+
+       @Override
+       public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
+               dispatchEvent("AllData", allData);
+       }
+
+       @Override
+       public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
+               dispatchEvent("SimpleProgress", simpleProgress);
+       }
+
+       @Override
+       public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
+               dispatchEvent("StartedCompression", startedCompression);
+       }
+
+       @Override
+       public void receivedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {
+               dispatchEvent("FinishedCompression", finishedCompression);
+       }
+
+       @Override
+       public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
+               dispatchEvent("UnknownPeerNoteType", unknownPeerNoteType);
+       }
+
+       @Override
+       public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
+               dispatchEvent("UnknownNodeIdentifier", unknownNodeIdentifier);
+       }
+
+       @Override
+       public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
+               dispatchEvent("ConfigData", configData);
+       }
+
+       @Override
+       public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
+               dispatchEvent("GetFailed", getFailed);
+       }
+
+       @Override
+       public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
+               dispatchEvent("PutFailed", putFailed);
+       }
+
+       @Override
+       public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
+               dispatchEvent("IdentifierCollision", identifierCollision);
+       }
+
+       @Override
+       public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
+               dispatchEvent("PersistentPutDir", persistentPutDir);
+       }
+
+       @Override
+       public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
+               dispatchEvent("PersistentRequestRemoved", persistentRequestRemoved);
+       }
+
+       @Override
+       public void receivedSubscribedUSK(FcpConnection fcpConnection, SubscribedUSK subscribedUSK) {
+               dispatchEvent("SubscribedUSK", subscribedUSK);
+       }
+
+       @Override
+       public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
+               dispatchEvent("SubscribedUSKUpdate", subscribedUSKUpdate);
+       }
+
+       @Override
+       public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
+               dispatchEvent("PluginInfo", pluginInfo);
+       }
+
+       @Override
+       public void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved) {
+               dispatchEvent("PluginRemoved", pluginRemoved);
+       }
+
+       @Override
+       public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
+               dispatchEvent("FCPPluginReply", fcpPluginReply);
+       }
+
+       @Override
+       public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
+               dispatchEvent("PersistentRequestModified", persistentRequestModified);
+       }
+
+       @Override
+       public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
+               dispatchEvent("PutSuccessful", putSuccessful);
+       }
+
+       @Override
+       public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
+               dispatchEvent("PutFetchable", putFetchable);
+       }
+
+       @Override
+       public void receivedSentFeed(FcpConnection source, SentFeed sentFeed) {
+               dispatchEvent("SentFeed", sentFeed);
+       }
+
+       @Override
+       public void receivedBookmarkFeed(FcpConnection fcpConnection, ReceivedBookmarkFeed receivedBookmarkFeed) {
+               dispatchEvent("ReceivedBookmarkFeed", receivedBookmarkFeed);
+       }
+
+       @Override
+       public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
+               dispatchEvent("ProtocolError", protocolError);
+       }
+
+       @Override
+       public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
+               dispatchEvent("Message", fcpMessage);
+       }
+
+       @Override
+       public void connectionClosed(FcpConnection fcpConnection, Throwable throwable) {
+               dispatchEvent("ConnectionClosed", throwable);
+       }
+
+       private void dispatchEvent(String name, Object message) {
+               eventListeners.getOrDefault(name, emptyList()).forEach(eventListener -> eventListener.accept(message));
+       }
+
+       private final Map<String, List<Consumer<Object>>> eventListeners = new HashMap<>();
+
+}
diff --git a/src/test/java/net/pterodactylus/fcp/DispatchingFcpAdapterTest.java b/src/test/java/net/pterodactylus/fcp/DispatchingFcpAdapterTest.java
new file mode 100644 (file)
index 0000000..6fdf0da
--- /dev/null
@@ -0,0 +1,250 @@
+package net.pterodactylus.fcp;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+
+public class DispatchingFcpAdapterTest {
+
+       @Test
+       public void nodeHelloIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("NodeHello", new NodeHello(null), (adapter, message) -> adapter.receivedNodeHello(null, message));
+       }
+
+       @Test
+       public void closedConnectionDuplicateClientNameIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("CloseConnectionDuplicateClientName", new CloseConnectionDuplicateClientName(null), (adapter, message) -> adapter.receivedCloseConnectionDuplicateClientName(null, message));
+       }
+
+       @Test
+       public void sskKeypairIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("SSKKeypair", new SSKKeypair(null), (adapter, message) -> adapter.receivedSSKKeypair(null, message));
+       }
+
+       @Test
+       public void peerIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("Peer", new Peer(null), (adapter, message) -> adapter.receivedPeer(null, message));
+       }
+
+       @Test
+       public void endListPeersIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("EndListPeers", new EndListPeers(null), (adapter, message) -> adapter.receivedEndListPeers(null, message));
+       }
+
+       @Test
+       public void peerNoteIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PeerNote", new PeerNote(null), (adapter, message) -> adapter.receivedPeerNote(null, message));
+       }
+
+       @Test
+       public void endListPeerNotesIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("EndListPeerNotes", new EndListPeerNotes(null), (adapter, message) -> adapter.receivedEndListPeerNotes(null, message));
+       }
+
+       @Test
+       public void peerRemovedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PeerRemoved", new PeerRemoved(null), (adapter, message) -> adapter.receivedPeerRemoved(null, message));
+       }
+
+       @Test
+       public void nodeDataIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("NodeData", createNodeDataMessage(), (adapter, message) -> adapter.receivedNodeData(null, message));
+       }
+
+       private NodeData createNodeDataMessage() {
+               FcpMessage receivedMessage = new FcpMessage("");
+               receivedMessage.setField("ark.pubURI", "");
+               receivedMessage.setField("ark.number", "0");
+               receivedMessage.setField("auth.negTypes", "0");
+               receivedMessage.setField("version", "0,1,2,3");
+               receivedMessage.setField("lastGoodVersion", "0,1,2,3");
+               return new NodeData(receivedMessage);
+       }
+
+       @Test
+       public void testDDAReplyIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("TestDDAReply", new TestDDAReply(null), (adapter, message) -> adapter.receivedTestDDAReply(null, message));
+       }
+
+       @Test
+       public void testDDACompleteIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("TestDDAComplete", new TestDDAComplete(null), (adapter, message) -> adapter.receivedTestDDAComplete(null, message));
+       }
+
+       @Test
+       public void persistentGetIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PersistentGet", new PersistentGet(null), (adapter, message) -> adapter.receivedPersistentGet(null, message));
+       }
+
+       @Test
+       public void persistentPutIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PersistentPut", new PersistentPut(null), (adapter, message) -> adapter.receivedPersistentPut(null, message));
+       }
+
+       @Test
+       public void endListPersistentRequestsIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("EndListPersistentRequests", new EndListPersistentRequests(null), (adapter, message) -> adapter.receivedEndListPersistentRequests(null, message));
+       }
+
+       @Test
+       public void uriGeneratedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("URIGenerated", new URIGenerated(null), (adapter, message) -> adapter.receivedURIGenerated(null, message));
+       }
+
+       @Test
+       public void dataFoundIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("DataFound", new DataFound(null), (adapter, message) -> adapter.receivedDataFound(null, message));
+       }
+
+       @Test
+       public void allDataIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("AllData", new AllData(null, null), (adapter, message) -> adapter.receivedAllData(null, message));
+       }
+
+       @Test
+       public void simpleProgressIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("SimpleProgress", new SimpleProgress(null), (adapter, message) -> adapter.receivedSimpleProgress(null, message));
+       }
+
+       @Test
+       public void startedCompressionIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("StartedCompression", new StartedCompression(null), (adapter, message) -> adapter.receivedStartedCompression(null, message));
+       }
+
+       @Test
+       public void finishedCompressionIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("FinishedCompression", new FinishedCompression(null), (adapter, message) -> adapter.receivedFinishedCompression(null, message));
+       }
+
+       @Test
+       public void unknownPeerNoteTypeIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("UnknownPeerNoteType", new UnknownPeerNoteType(null), (adapter, message) -> adapter.receivedUnknownPeerNoteType(null, message));
+       }
+
+       @Test
+       public void unknownNodeIdentifierIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("UnknownNodeIdentifier", new UnknownNodeIdentifier(null), (adapter, message) -> adapter.receivedUnknownNodeIdentifier(null, message));
+       }
+
+       @Test
+       public void configDataIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("ConfigData", new ConfigData(null), (adapter, message) -> adapter.receivedConfigData(null, message));
+       }
+
+       @Test
+       public void getFailedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("GetFailed", new GetFailed(null), (adapter, message) -> adapter.receivedGetFailed(null, message));
+       }
+
+       @Test
+       public void putFailedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PutFailed", new PutFailed(null), (adapter, message) -> adapter.receivedPutFailed(null, message));
+       }
+
+       @Test
+       public void identifierCollisionIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("IdentifierCollision", new IdentifierCollision(null), (adapter, message) -> adapter.receivedIdentifierCollision(null, message));
+       }
+
+       @Test
+       public void persistentPutDirIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PersistentPutDir", new PersistentPutDir(null), (adapter, message) -> adapter.receivedPersistentPutDir(null, message));
+       }
+
+       @Test
+       public void persistentRequestRemovedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PersistentRequestRemoved", new PersistentRequestRemoved(null), (adapter, message) -> adapter.receivedPersistentRequestRemoved(null, message));
+       }
+
+       @Test
+       public void subscribedUSKIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("SubscribedUSK", new SubscribedUSK(null), (adapter, message) -> adapter.receivedSubscribedUSK(null, message));
+       }
+
+       @Test
+       public void subscribedUSKUpdateIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("SubscribedUSKUpdate", new SubscribedUSKUpdate(null), (adapter, message) -> adapter.receivedSubscribedUSKUpdate(null, message));
+       }
+
+       @Test
+       public void pluginInfoIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PluginInfo", new PluginInfo(null), (adapter, message) -> adapter.receivedPluginInfo(null, message));
+       }
+
+       @Test
+       public void pluginRemovedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PluginRemoved", new PluginRemoved(null), (adapter, message) -> adapter.receivedPluginRemoved(null, message));
+       }
+
+       @Test
+       public void fcpPluginReplyIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("FCPPluginReply", new FCPPluginReply(null, null), (adapter, message) -> adapter.receivedFCPPluginReply(null, message));
+       }
+
+       @Test
+       public void persistentRequestModifiedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PersistentRequestModified", new PersistentRequestModified(null), (adapter, message) -> adapter.receivedPersistentRequestModified(null, message));
+       }
+
+       @Test
+       public void putSuccessfulIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PutSuccessful", new PutSuccessful(null), (adapter, message) -> adapter.receivedPutSuccessful(null, message));
+       }
+
+       @Test
+       public void putFetchableIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("PutFetchable", new PutFetchable(null), (adapter, message) -> adapter.receivedPutFetchable(null, message));
+       }
+
+       @Test
+       public void sentFeedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("SentFeed", new SentFeed(null), (adapter, message) -> adapter.receivedSentFeed(null, message));
+       }
+
+       @Test
+       public void receivedBookmarkFeedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("ReceivedBookmarkFeed", new ReceivedBookmarkFeed(null), (adapter, message) -> adapter.receivedBookmarkFeed(null, message));
+       }
+
+       @Test
+       public void protocolErrorIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("ProtocolError", new ProtocolError(null), (adapter, message) -> adapter.receivedProtocolError(null, message));
+       }
+
+       @Test
+       public void messageIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("Message", new FcpMessage(null), (adapter, message) -> adapter.receivedMessage(null, message));
+       }
+
+       @Test
+       public void connectionClosedIsDispatchedCorrectly() {
+               dispatchMessageAndVerifyDispatch("ConnectionClosed", new Exception("Test"), (adapter, throwable) -> adapter.connectionClosed(null, throwable));
+       }
+
+       @Test
+       public void multipleListenersCanBeAttachedToOneMessage() {
+               DispatchingFcpAdapter adapter = new DispatchingFcpAdapter();
+               List<Object> receivedMessages = new ArrayList<>();
+               adapter.addListener("Message", receivedMessages::add);
+               adapter.addListener("Message", receivedMessages::add);
+               FcpMessage message = new FcpMessage("Test");
+               adapter.receivedMessage(null, message);
+               assertThat(receivedMessages, contains(message, message));
+       }
+
+       private <T> void dispatchMessageAndVerifyDispatch(String messageName, T message, BiConsumer<FcpListener, T> messageDispatcher) {
+               DispatchingFcpAdapter adapter = new DispatchingFcpAdapter();
+               AtomicReference<Object> receivedMessage = new AtomicReference<>();
+               adapter.addListener(messageName, receivedMessage::set);
+               messageDispatcher.accept(adapter, message);
+               assertThat(receivedMessage.get(), equalTo(message));
+       }
+
+}