Replace utils’ Pair by custom containers.
[Sone.git] / src / main / java / net / pterodactylus / sone / freenet / plugin / PluginConnector.java
1 /*
2  * Sone - PluginConnector.java - Copyright © 2010–2012 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.freenet.plugin;
19
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import com.google.inject.Inject;
25
26 import freenet.pluginmanager.FredPluginTalker;
27 import freenet.pluginmanager.PluginNotFoundException;
28 import freenet.pluginmanager.PluginRespirator;
29 import freenet.pluginmanager.PluginTalker;
30 import freenet.support.SimpleFieldSet;
31 import freenet.support.api.Bucket;
32
33 /**
34  * Interface for talking to other plugins. Other plugins are identified by their
35  * name and a unique connection identifier.
36  *
37  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
38  */
39 public class PluginConnector implements FredPluginTalker {
40
41         /** The plugin respirator. */
42         private final PluginRespirator pluginRespirator;
43
44         /** Connector listener managers for all plugin connections. */
45         private final Map<PluginIdentifier, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap<PluginIdentifier, ConnectorListenerManager>());
46
47         /**
48          * Creates a new plugin connector.
49          *
50          * @param pluginRespirator
51          *            The plugin respirator
52          */
53         @Inject
54         public PluginConnector(PluginRespirator pluginRespirator) {
55                 this.pluginRespirator = pluginRespirator;
56         }
57
58         //
59         // LISTENER MANAGEMENT
60         //
61
62         /**
63          * Adds a connection listener for the given plugin connection.
64          *
65          * @param pluginName
66          *            The name of the plugin
67          * @param identifier
68          *            The identifier of the connection
69          * @param connectorListener
70          *            The listener to add
71          */
72         public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) {
73                 getConnectorListenerManager(pluginName, identifier).addListener(connectorListener);
74         }
75
76         /**
77          * Removes a connection listener for the given plugin connection.
78          *
79          * @param pluginName
80          *            The name of the plugin
81          * @param identifier
82          *            The identifier of the connection
83          * @param connectorListener
84          *            The listener to remove
85          */
86         public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) {
87                 getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener);
88         }
89
90         //
91         // ACTIONS
92         //
93
94         /**
95          * Sends a request to the given plugin.
96          *
97          * @param pluginName
98          *            The name of the plugin
99          * @param identifier
100          *            The identifier of the connection
101          * @param fields
102          *            The fields of the message
103          * @throws PluginException
104          *             if the plugin can not be found
105          */
106         public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields) throws PluginException {
107                 sendRequest(pluginName, identifier, fields, null);
108         }
109
110         /**
111          * Sends a request to the given plugin.
112          *
113          * @param pluginName
114          *            The name of the plugin
115          * @param identifier
116          *            The identifier of the connection
117          * @param fields
118          *            The fields of the message
119          * @param data
120          *            The payload of the message (may be null)
121          * @throws PluginException
122          *             if the plugin can not be found
123          */
124         public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields, Bucket data) throws PluginException {
125                 getPluginTalker(pluginName, identifier).send(fields, data);
126         }
127
128         //
129         // PRIVATE METHODS
130         //
131
132         /**
133          * Returns the connection listener manager for the given plugin connection,
134          * creating a new one if none does exist yet.
135          *
136          * @param pluginName
137          *            The name of the plugin
138          * @param identifier
139          *            The identifier of the connection
140          * @return The connection listener manager
141          */
142         private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) {
143                 return getConnectorListenerManager(pluginName, identifier, true);
144         }
145
146         /**
147          * Returns the connection listener manager for the given plugin connection,
148          * optionally creating a new one if none does exist yet.
149          *
150          * @param pluginName
151          *            The name of the plugin
152          * @param identifier
153          *            The identifier of the connection
154          * @param create
155          *            {@code true} to create a new manager if there is none,
156          *            {@code false} to return {@code null} in that case
157          * @return The connection listener manager, or {@code null} if none existed
158          *         and {@code create} is {@code false}
159          */
160         private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) {
161                 ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new PluginIdentifier(pluginName, identifier));
162                 if (create && (connectorListenerManager == null)) {
163                         connectorListenerManager = new ConnectorListenerManager(this);
164                         connectorListenerManagers.put(new PluginIdentifier(pluginName, identifier), connectorListenerManager);
165                 }
166                 return connectorListenerManager;
167         }
168
169         /**
170          * Returns the plugin talker for the given plugin connection.
171          *
172          * @param pluginName
173          *            The name of the plugin
174          * @param identifier
175          *            The identifier of the connection
176          * @return The plugin talker
177          * @throws PluginException
178          *             if the plugin can not be found
179          */
180         private PluginTalker getPluginTalker(String pluginName, String identifier) throws PluginException {
181                 try {
182                         return pluginRespirator.getPluginTalker(this, pluginName, identifier);
183                 } catch (PluginNotFoundException pnfe1) {
184                         throw new PluginException(pnfe1);
185                 }
186         }
187
188         //
189         // INTERFACE FredPluginTalker
190         //
191
192         /**
193          * {@inheritDoc}
194          */
195         @Override
196         public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) {
197                 ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false);
198                 if (connectorListenerManager == null) {
199                         /* we don’t care about events for this plugin. */
200                         return;
201                 }
202                 connectorListenerManager.fireReceivedReply(params, data);
203         }
204
205         /**
206          * Container for identifying plugins. Plugins are identified by their plugin
207          * name and their unique identifier.
208          *
209          * @author <a href="mailto:d.roden@xplosion.de">David Roden</a>
210          */
211         private static class PluginIdentifier {
212
213                 /** The plugin name. */
214                 private final String pluginName;
215
216                 /** The plugin identifier. */
217                 private final String identifier;
218
219                 /**
220                  * Creates a new plugin identifier.
221                  *
222                  * @param pluginName
223                  *            The name of the plugin
224                  * @param identifier
225                  *            The identifier of the plugin
226                  */
227                 public PluginIdentifier(String pluginName, String identifier) {
228                         this.pluginName = pluginName;
229                         this.identifier = identifier;
230                 }
231
232                 //
233                 // OBJECT METHODS
234                 //
235
236                 /**
237                  * {@inheritDoc}
238                  */
239                 @Override
240                 public int hashCode() {
241                         return pluginName.hashCode() ^ identifier.hashCode();
242                 }
243
244                 /**
245                  * {@inheritDoc}
246                  */
247                 @Override
248                 public boolean equals(Object object) {
249                         if (!(object instanceof PluginIdentifier)) {
250                                 return false;
251                         }
252                         PluginIdentifier pluginIdentifier = (PluginIdentifier) object;
253                         return pluginName.equals(pluginIdentifier.pluginName) && identifier.equals(pluginIdentifier.identifier);
254                 }
255
256         }
257
258 }