From 64d4f133925b0b8aac6f4dd225500d326f20ac41 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Thu, 17 Jan 2013 07:38:03 +0100 Subject: [PATCH] Convert plugin replies to EventBus-based events. --- .../sone/freenet/plugin/ConnectorListener.java | 50 ------- .../freenet/plugin/ConnectorListenerManager.java | 60 --------- .../sone/freenet/plugin/PluginConnector.java | 145 ++------------------- .../freenet/plugin/event/ReceivedReplyEvent.java | 117 +++++++++++++++++ .../sone/freenet/wot/WebOfTrustConnector.java | 105 ++++++++++++--- 5 files changed, 213 insertions(+), 264 deletions(-) delete mode 100644 src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java delete mode 100644 src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java create mode 100644 src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java deleted file mode 100644 index 76a5497..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Sone - ConnectorListener.java - Copyright © 2010–2012 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 3 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, see . - */ - -package net.pterodactylus.sone.freenet.plugin; - -import java.util.EventListener; - -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Interface for objects that want to be notified if a {@link PluginConnector} - * receives a reply from a plugin. As a connection listener is always - * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener) - * added} for a specific plugin, it will always be notified for replies from the - * correct plugin (unless you register the same listener for multiple - * plugins—which you subsequently should not do). - * - * @author David ‘Bombe’ Roden - */ -public interface ConnectorListener extends EventListener { - - /** - * A reply was received from the plugin this connection listener was added - * for. - * - * @param pluginConnector - * The plugin connector that received the reply - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data); - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java deleted file mode 100644 index 742a514..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Sone - ConnectorListenerManager.java - Copyright © 2010–2012 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 3 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, see . - */ - -package net.pterodactylus.sone.freenet.plugin; - -import net.pterodactylus.util.event.AbstractListenerManager; -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Manages {@link ConnectorListener}s and fire events. - * - * @author David ‘Bombe’ Roden - */ -public class ConnectorListenerManager extends AbstractListenerManager { - - /** - * Creates a new manager for {@link ConnectorListener}s. - * - * @param pluginConnector - * The plugin connector that is the source for all events - */ - public ConnectorListenerManager(PluginConnector pluginConnector) { - super(pluginConnector); - } - - // - // ACTIONS - // - - /** - * Notifies all registered listeners that a reply from the plugin was - * received. - * - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void fireReceivedReply(SimpleFieldSet fields, Bucket data) { - for (ConnectorListener connectorListener : getListeners()) { - connectorListener.receivedReply(getSource(), fields, data); - } - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java index d556a6c..b842350 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java @@ -17,10 +17,9 @@ package net.pterodactylus.sone.freenet.plugin; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import net.pterodactylus.sone.freenet.plugin.event.ReceivedReplyEvent; +import com.google.common.eventbus.EventBus; import com.google.inject.Inject; import freenet.pluginmanager.FredPluginTalker; @@ -38,56 +37,27 @@ import freenet.support.api.Bucket; */ public class PluginConnector implements FredPluginTalker { + /** The event bus. */ + private final EventBus eventBus; + /** The plugin respirator. */ private final PluginRespirator pluginRespirator; - /** Connector listener managers for all plugin connections. */ - private final Map connectorListenerManagers = Collections.synchronizedMap(new HashMap()); - /** * Creates a new plugin connector. * + * @param eventBus + * The event bus * @param pluginRespirator * The plugin respirator */ @Inject - public PluginConnector(PluginRespirator pluginRespirator) { + public PluginConnector(EventBus eventBus, PluginRespirator pluginRespirator) { + this.eventBus = eventBus; this.pluginRespirator = pluginRespirator; } // - // LISTENER MANAGEMENT - // - - /** - * Adds a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to add - */ - public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).addListener(connectorListener); - } - - /** - * Removes a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to remove - */ - public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener); - } - - // // ACTIONS // @@ -130,43 +100,6 @@ public class PluginConnector implements FredPluginTalker { // /** - * Returns the connection listener manager for the given plugin connection, - * creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @return The connection listener manager - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) { - return getConnectorListenerManager(pluginName, identifier, true); - } - - /** - * Returns the connection listener manager for the given plugin connection, - * optionally creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param create - * {@code true} to create a new manager if there is none, - * {@code false} to return {@code null} in that case - * @return The connection listener manager, or {@code null} if none existed - * and {@code create} is {@code false} - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) { - ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new PluginIdentifier(pluginName, identifier)); - if (create && (connectorListenerManager == null)) { - connectorListenerManager = new ConnectorListenerManager(this); - connectorListenerManagers.put(new PluginIdentifier(pluginName, identifier), connectorListenerManager); - } - return connectorListenerManager; - } - - /** * Returns the plugin talker for the given plugin connection. * * @param pluginName @@ -194,65 +127,7 @@ public class PluginConnector implements FredPluginTalker { */ @Override public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) { - ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false); - if (connectorListenerManager == null) { - /* we don’t care about events for this plugin. */ - return; - } - connectorListenerManager.fireReceivedReply(params, data); - } - - /** - * Container for identifying plugins. Plugins are identified by their plugin - * name and their unique identifier. - * - * @author David Roden - */ - private static class PluginIdentifier { - - /** The plugin name. */ - private final String pluginName; - - /** The plugin identifier. */ - private final String identifier; - - /** - * Creates a new plugin identifier. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the plugin - */ - public PluginIdentifier(String pluginName, String identifier) { - this.pluginName = pluginName; - this.identifier = identifier; - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return pluginName.hashCode() ^ identifier.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object object) { - if (!(object instanceof PluginIdentifier)) { - return false; - } - PluginIdentifier pluginIdentifier = (PluginIdentifier) object; - return pluginName.equals(pluginIdentifier.pluginName) && identifier.equals(pluginIdentifier.identifier); - } - + eventBus.post(new ReceivedReplyEvent(this, pluginName, identifier, params, data)); } } diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java new file mode 100644 index 0000000..89a8df3 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java @@ -0,0 +1,117 @@ +/* + * Sone - ReceivedReplyEvent.java - Copyright © 2013 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 3 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, see . + */ + +package net.pterodactylus.sone.freenet.plugin.event; + +import net.pterodactylus.sone.freenet.plugin.PluginConnector; +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Event that signals that a plugin reply was received. + * + * @author David ‘Bombe’ Roden + */ +public class ReceivedReplyEvent { + + /** The connector that received the reply. */ + private final PluginConnector pluginConnector; + + /** The name of the plugin that sent the reply. */ + private final String pluginName; + + /** The identifier of the initial request. */ + private final String identifier; + + /** The fields containing the reply. */ + private final SimpleFieldSet fieldSet; + + /** The optional reply data. */ + private final Bucket data; + + /** + * Creates a new “reply received” event. + * + * @param pluginConnector + * The connector that received the event + * @param pluginName + * The name of the plugin that sent the reply + * @param identifier + * The identifier of the initial request + * @param fieldSet + * The fields containing the reply + * @param data + * The optional data of the reply + */ + public ReceivedReplyEvent(PluginConnector pluginConnector, String pluginName, String identifier, SimpleFieldSet fieldSet, Bucket data) { + this.pluginConnector = pluginConnector; + this.pluginName = pluginName; + this.identifier = identifier; + this.fieldSet = fieldSet; + this.data = data; + } + + // + // ACCESSORS + // + + /** + * Returns the plugin connector that received the reply. + * + * @return The plugin connector that received the reply + */ + public PluginConnector pluginConnector() { + return pluginConnector; + } + + /** + * Returns the name of the plugin that sent the reply. + * + * @return The name of the plugin that sent the reply + */ + public String pluginName() { + return pluginName; + } + + /** + * Returns the identifier of the initial request. + * + * @return The identifier of the initial request + */ + public String identifier() { + return identifier; + } + + /** + * Returns the fields containing the reply. + * + * @return The fields containing the reply + */ + public SimpleFieldSet fieldSet() { + return fieldSet; + } + + /** + * Returns the optional data of the reply. + * + * @return The optional data of the reply (may be {@code null}) + */ + public Bucket data() { + return data; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index 18dbaff..28c9f01 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -25,12 +25,14 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; -import net.pterodactylus.sone.freenet.plugin.ConnectorListener; import net.pterodactylus.sone.freenet.plugin.PluginConnector; import net.pterodactylus.sone.freenet.plugin.PluginException; +import net.pterodactylus.sone.freenet.plugin.event.ReceivedReplyEvent; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.number.Numbers; +import com.google.common.collect.MapMaker; +import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import freenet.support.SimpleFieldSet; @@ -55,6 +57,9 @@ public class WebOfTrustConnector { /** The plugin connector. */ private final PluginConnector pluginConnector; + /** Map for replies. */ + private final Map replies = new MapMaker().makeMap(); + /** * Creates a new Web of Trust connector that uses the given plugin * connector. @@ -384,24 +389,12 @@ public class WebOfTrustConnector { * if the request could not be sent */ private Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException { - final String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement(); - final Reply reply = new Reply(); + String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement(); + Reply reply = new Reply(); + PluginIdentifier pluginIdentifier = new PluginIdentifier(WOT_PLUGIN_NAME, identifier); + replies.put(pluginIdentifier, reply); + logger.log(Level.FINE, String.format("Sending FCP Request: %s", fields.get("Message"))); - ConnectorListener connectorListener = new ConnectorListener() { - - @Override - @SuppressWarnings("synthetic-access") - public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) { - String messageName = fields.get("Message"); - logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName)); - synchronized (reply) { - reply.setFields(fields); - reply.setData(data); - reply.notify(); - } - } - }; - pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener); synchronized (reply) { try { pluginConnector.sendRequest(WOT_PLUGIN_NAME, identifier, fields, data); @@ -413,7 +406,7 @@ public class WebOfTrustConnector { } } } finally { - pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener); + replies.remove(pluginIdentifier); } } logger.log(Level.FINEST, String.format("Received FCP Response for %s: %s", fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null)); @@ -424,6 +417,27 @@ public class WebOfTrustConnector { } /** + * Notifies the connector that a plugin reply was received. + * + * @param receivedReplyEvent + * The event + */ + @Subscribe + public void receivedReply(ReceivedReplyEvent receivedReplyEvent) { + PluginIdentifier pluginIdentifier = new PluginIdentifier(receivedReplyEvent.pluginName(), receivedReplyEvent.identifier()); + Reply reply = replies.remove(pluginIdentifier); + if (reply == null) { + return; + } + logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", receivedReplyEvent.fieldSet().get("Message"))); + synchronized (reply) { + reply.setFields(receivedReplyEvent.fieldSet()); + reply.setData(receivedReplyEvent.data()); + reply.notify(); + } + } + + /** * Container for the data of the reply from a plugin. * * @author David ‘Bombe’ Roden @@ -558,4 +572,57 @@ public class WebOfTrustConnector { } + /** + * Container for identifying plugins. Plugins are identified by their plugin + * name and their unique identifier. + * + * @author David Roden + */ + private static class PluginIdentifier { + + /** The plugin name. */ + private final String pluginName; + + /** The plugin identifier. */ + private final String identifier; + + /** + * Creates a new plugin identifier. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the plugin + */ + public PluginIdentifier(String pluginName, String identifier) { + this.pluginName = pluginName; + this.identifier = identifier; + } + + // + // OBJECT METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return pluginName.hashCode() ^ identifier.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof PluginIdentifier)) { + return false; + } + PluginIdentifier pluginIdentifier = (PluginIdentifier) object; + return pluginName.equals(pluginIdentifier.pluginName) && identifier.equals(pluginIdentifier.identifier); + } + + } + } -- 2.7.4