* {@inheritDoc}
*/
@Override
+ public void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved) {
+ /* empty. */
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
/* empty. */
}
}
} 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)) {
*/
public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo);
+ void receivedPluginRemoved(FcpConnection fcpConnection, PluginRemoved pluginRemoved);
+
/**
* Notifies a listener that an “FCPPluginReply“ message was received.
*
}
}
+ public void fireReceivedPluginRemoved(PluginRemoved pluginRemoved) {
+ for (FcpListener fcpListener : getListeners()) {
+ fcpListener.receivedPluginRemoved(getSource(), pluginRemoved);
+ }
+ }
+
/**
* Notifies all listeners that an “FCPPluginReply” message was received.
*
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+package net.pterodactylus.fcp;
+
+/**
+ * The “RemovePlugin” message is used to remove a plugin.
+ *
+ * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe’ Roden</a>
+ */
+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));
+ }
+
+}
return new ReloadPluginCommandImpl(threadPool, this::connect);
}
+ @Override
+ public RemovePluginCommand removePlugin() {
+ return new RemovePluginCommandImpl(threadPool, this::connect);
+ }
+
}
LoadPluginCommand loadPlugin();
ReloadPluginCommand reloadPlugin();
+ RemovePluginCommand removePlugin();
}
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;
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);
}
--- /dev/null
+package net.pterodactylus.fcp.quelaton;
+
+/**
+ * Removes a plugin.
+ *
+ * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe’ Roden</a>
+ */
+public interface RemovePluginCommand {
+
+ Executable<Boolean> plugin(String pluginClass);
+
+}
--- /dev/null
+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 <a href="mailto:bombe@freenetproject.org">David ‘Bombe’ Roden</a>
+ */
+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<Boolean> plugin(String pluginClass) {
+ removePlugin.setPluginName(pluginClass);
+ return this::execute;
+ }
+
+ private ListenableFuture<Boolean> 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<Boolean> {
+
+ 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);
+ }
+
+ }
+
+}
public class PluginCommands {
+ private static final String CLASS_NAME = "foo.plugin.Plugin";
+
private List<String> lines;
private String identifier;
public class ReloadPlugin {
- private static final String CLASS_NAME = "foo.plugin.Plugin";
-
@Test
public void reloadingPluginWorks() throws InterruptedException, ExecutionException, IOException {
Future<Optional<PluginInfo>> pluginInfo = fcpClient.reloadPlugin().plugin(CLASS_NAME).execute();
}
+ public class RemovePlugin {
+
+ @Test
+ public void removingPluginWorks() throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> 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<List<String>> matchPluginRemovedMessage() {
+ return matchesFcpMessage(
+ "RemovePlugin",
+ "Identifier=" + identifier,
+ "PluginName=" + CLASS_NAME,
+ "EndMessage"
+ );
+ }
+
+ }
+
}
}