From 945cbadf07f467f1ae677ee4147988e6fcd7e8fc Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 21 Aug 2015 23:51:01 +0200 Subject: [PATCH] Add command that removes a plugin --- .../java/net/pterodactylus/fcp/FcpAdapter.java | 8 +++ .../java/net/pterodactylus/fcp/FcpConnection.java | 2 + .../java/net/pterodactylus/fcp/FcpListener.java | 2 + .../net/pterodactylus/fcp/FcpListenerManager.java | 6 ++ .../java/net/pterodactylus/fcp/PluginRemoved.java | 57 +++++++++++++++ .../java/net/pterodactylus/fcp/RemovePlugin.java | 27 ++++++++ .../fcp/quelaton/DefaultFcpClient.java | 5 ++ .../net/pterodactylus/fcp/quelaton/FcpClient.java | 1 + .../net/pterodactylus/fcp/quelaton/FcpDialog.java | 8 +++ .../fcp/quelaton/RemovePluginCommand.java | 12 ++++ .../fcp/quelaton/RemovePluginCommandImpl.java | 81 ++++++++++++++++++++++ .../fcp/quelaton/DefaultFcpClientTest.java | 34 ++++++++- 12 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/pterodactylus/fcp/PluginRemoved.java create mode 100644 src/main/java/net/pterodactylus/fcp/RemovePlugin.java create mode 100644 src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommand.java create mode 100644 src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommandImpl.java diff --git a/src/main/java/net/pterodactylus/fcp/FcpAdapter.java b/src/main/java/net/pterodactylus/fcp/FcpAdapter.java index 063d363..fc2b578 100644 --- a/src/main/java/net/pterodactylus/fcp/FcpAdapter.java +++ b/src/main/java/net/pterodactylus/fcp/FcpAdapter.java @@ -273,6 +273,14 @@ public class FcpAdapter implements FcpListener { * {@inheritDoc} */ @Override + public void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved) { + /* empty. */ + } + + /** + * {@inheritDoc} + */ + @Override public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) { /* empty. */ } diff --git a/src/main/java/net/pterodactylus/fcp/FcpConnection.java b/src/main/java/net/pterodactylus/fcp/FcpConnection.java index cc13d4a..ac4d17b 100644 --- a/src/main/java/net/pterodactylus/fcp/FcpConnection.java +++ b/src/main/java/net/pterodactylus/fcp/FcpConnection.java @@ -301,6 +301,8 @@ public class FcpConnection implements Closeable { } } else if ("PluginInfo".equals(messageName)) { fcpListenerManager.fireReceivedPluginInfo(new PluginInfo(fcpMessage)); + } else if ("PluginRemoved".equals(messageName)) { + fcpListenerManager.fireReceivedPluginRemoved(new PluginRemoved(fcpMessage)); } else if ("NodeData".equals(messageName)) { fcpListenerManager.fireReceivedNodeData(new NodeData(fcpMessage)); } else if ("TestDDAReply".equals(messageName)) { diff --git a/src/main/java/net/pterodactylus/fcp/FcpListener.java b/src/main/java/net/pterodactylus/fcp/FcpListener.java index 02eeed5..91e1f9c 100644 --- a/src/main/java/net/pterodactylus/fcp/FcpListener.java +++ b/src/main/java/net/pterodactylus/fcp/FcpListener.java @@ -329,6 +329,8 @@ public interface FcpListener extends EventListener { */ public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo); + void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved); + /** * Notifies a listener that an “FCPPluginReply“ message was received. * diff --git a/src/main/java/net/pterodactylus/fcp/FcpListenerManager.java b/src/main/java/net/pterodactylus/fcp/FcpListenerManager.java index 7969da1..a5c27af 100644 --- a/src/main/java/net/pterodactylus/fcp/FcpListenerManager.java +++ b/src/main/java/net/pterodactylus/fcp/FcpListenerManager.java @@ -466,6 +466,12 @@ public class FcpListenerManager { } } + public void fireReceivedPluginRemoved(PluginRemoved pluginRemoved) { + for (FcpListener fcpListener : getListeners()) { + fcpListener.receivedPluginRemoved(getSource(), pluginRemoved); + } + } + /** * Notifies all listeners that an “FCPPluginReply” message was received. * diff --git a/src/main/java/net/pterodactylus/fcp/PluginRemoved.java b/src/main/java/net/pterodactylus/fcp/PluginRemoved.java new file mode 100644 index 0000000..7492954 --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/PluginRemoved.java @@ -0,0 +1,57 @@ +/* + * jFCPlib - PluginInfo.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.fcp; + +/** + * The “PluginRemoved” message is a reply to the {@link RemovePlugin} request. + * + * @author David ‘Bombe’ Roden <bombe@freenetproject.org> + */ +public class PluginRemoved extends BaseMessage implements Identifiable { + + /** + * Creates a new “PluginRemoved” message that wraps the received message. + * + * @param receivedMessage + * The received message + */ + public PluginRemoved(FcpMessage receivedMessage) { + super(receivedMessage); + } + + /** + * Returns the name of the plugin. + * + * @return The name of the plugin + */ + public String getPluginName() { + return getField("PluginName"); + } + + /** + * Returns the identifier of the request. + * + * @return The identifier of the request + */ + @Override + public String getIdentifier() { + return getField("Identifier"); + } + +} diff --git a/src/main/java/net/pterodactylus/fcp/RemovePlugin.java b/src/main/java/net/pterodactylus/fcp/RemovePlugin.java new file mode 100644 index 0000000..44fa9a7 --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/RemovePlugin.java @@ -0,0 +1,27 @@ +package net.pterodactylus.fcp; + +/** + * The “RemovePlugin” message is used to remove a plugin. + * + * @author David ‘Bombe’ Roden + */ +public class RemovePlugin extends FcpMessage { + + public RemovePlugin(String identifier) { + super("RemovePlugin"); + setField("Identifier", identifier); + } + + public void setPluginName(String pluginName) { + setField("PluginName", pluginName); + } + + public void setMaxWaitTime(int maxWaitTime) { + setField("MaxWaitTime", String.valueOf(maxWaitTime)); + } + + public void setPurge(boolean purge) { + setField("Purge", String.valueOf(purge)); + } + +} diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java index 2f0cc35..3f485c0 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/DefaultFcpClient.java @@ -124,5 +124,10 @@ public class DefaultFcpClient implements FcpClient { return new ReloadPluginCommandImpl(threadPool, this::connect); } + @Override + public RemovePluginCommand removePlugin() { + return new RemovePluginCommandImpl(threadPool, this::connect); + } + } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java b/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java index 0091866..67c11ee 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/FcpClient.java @@ -26,5 +26,6 @@ public interface FcpClient { LoadPluginCommand loadPlugin(); ReloadPluginCommand reloadPlugin(); + RemovePluginCommand removePlugin(); } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/FcpDialog.java b/src/main/java/net/pterodactylus/fcp/quelaton/FcpDialog.java index 47319f0..5be102c 100644 --- a/src/main/java/net/pterodactylus/fcp/quelaton/FcpDialog.java +++ b/src/main/java/net/pterodactylus/fcp/quelaton/FcpDialog.java @@ -36,6 +36,7 @@ import net.pterodactylus.fcp.PersistentPutDir; import net.pterodactylus.fcp.PersistentRequestModified; import net.pterodactylus.fcp.PersistentRequestRemoved; import net.pterodactylus.fcp.PluginInfo; +import net.pterodactylus.fcp.PluginRemoved; import net.pterodactylus.fcp.ProtocolError; import net.pterodactylus.fcp.PutFailed; import net.pterodactylus.fcp.PutFetchable; @@ -369,6 +370,13 @@ public abstract class FcpDialog implements AutoCloseable, FcpListener { protected void consumePluginInfo(PluginInfo pluginInfo) { } @Override + public final void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved) { + consume(this::consumePluginRemoved, pluginRemoved); + } + + protected void consumePluginRemoved(PluginRemoved pluginRemoved) { } + + @Override public final void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) { consume(this::consumeFCPPluginReply, fcpPluginReply); } diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommand.java b/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommand.java new file mode 100644 index 0000000..c221592 --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommand.java @@ -0,0 +1,12 @@ +package net.pterodactylus.fcp.quelaton; + +/** + * Removes a plugin. + * + * @author David ‘Bombe’ Roden + */ +public interface RemovePluginCommand { + + Executable plugin(String pluginClass); + +} diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommandImpl.java b/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommandImpl.java new file mode 100644 index 0000000..b4a6b79 --- /dev/null +++ b/src/main/java/net/pterodactylus/fcp/quelaton/RemovePluginCommandImpl.java @@ -0,0 +1,81 @@ +package net.pterodactylus.fcp.quelaton; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; + +import net.pterodactylus.fcp.PluginRemoved; +import net.pterodactylus.fcp.ProtocolError; +import net.pterodactylus.fcp.RemovePlugin; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Default {@link RemovePluginCommand} implementation based on {@link FcpDialog}. + * + * @author David ‘Bombe’ Roden + */ +public class RemovePluginCommandImpl implements RemovePluginCommand { + + private static final RandomIdentifierGenerator IDENTIFIER = new RandomIdentifierGenerator(); + private final ListeningExecutorService threadPool; + private final ConnectionSupplier connectionSupplier; + private final RemovePlugin removePlugin = new RemovePlugin(IDENTIFIER.generate()); + + public RemovePluginCommandImpl(ExecutorService threadPool, ConnectionSupplier connectionSupplier) { + this.threadPool = MoreExecutors.listeningDecorator(threadPool); + this.connectionSupplier = connectionSupplier; + } + + @Override + public Executable plugin(String pluginClass) { + removePlugin.setPluginName(pluginClass); + return this::execute; + } + + private ListenableFuture execute() { + return threadPool.submit(this::executeDialog); + } + + private boolean executeDialog() throws IOException, ExecutionException, InterruptedException { + try (RemovePluginDialog removePluginDialog = new RemovePluginDialog()) { + return removePluginDialog.send(removePlugin).get(); + } + } + + private class RemovePluginDialog extends FcpDialog { + + private final AtomicBoolean finished = new AtomicBoolean(); + private final AtomicBoolean pluginRemoved = new AtomicBoolean(); + + public RemovePluginDialog() throws IOException { + super(threadPool, connectionSupplier.get()); + } + + @Override + protected boolean isFinished() { + return finished.get(); + } + + @Override + protected Boolean getResult() { + return pluginRemoved.get(); + } + + @Override + protected void consumePluginRemoved(PluginRemoved pluginRemoved) { + this.pluginRemoved.set(true); + finished.set(true); + } + + @Override + protected void consumeProtocolError(ProtocolError protocolError) { + finished.set(true); + } + + } + +} diff --git a/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java b/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java index 6cc61d6..fafee42 100644 --- a/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java +++ b/src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java @@ -1995,6 +1995,8 @@ public class DefaultFcpClientTest { public class PluginCommands { + private static final String CLASS_NAME = "foo.plugin.Plugin"; + private List lines; private String identifier; @@ -2141,8 +2143,6 @@ public class DefaultFcpClientTest { public class ReloadPlugin { - private static final String CLASS_NAME = "foo.plugin.Plugin"; - @Test public void reloadingPluginWorks() throws InterruptedException, ExecutionException, IOException { Future> pluginInfo = fcpClient.reloadPlugin().plugin(CLASS_NAME).execute(); @@ -2192,6 +2192,36 @@ public class DefaultFcpClientTest { } + public class RemovePlugin { + + @Test + public void removingPluginWorks() throws InterruptedException, ExecutionException, IOException { + Future pluginRemoved = fcpClient.removePlugin().plugin(CLASS_NAME).execute(); + connectAndAssert(() -> matchPluginRemovedMessage()); + replyWithPluginRemoved(); + assertThat(pluginRemoved.get(), is(true)); + } + + private void replyWithPluginRemoved() throws IOException { + fcpServer.writeLine( + "PluginRemoved", + "Identifier=" + identifier, + "PluginName=" + CLASS_NAME, + "EndMessage" + ); + } + + private Matcher> matchPluginRemovedMessage() { + return matchesFcpMessage( + "RemovePlugin", + "Identifier=" + identifier, + "PluginName=" + CLASS_NAME, + "EndMessage" + ); + } + + } + } } -- 2.7.4