delete connect callback as soon as its result was set
[jFCPlib.git] / src / net / pterodactylus / fcp / highlevel / HighLevelClient.java
1 /*
2  * fcplib - HighLevelClient.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package net.pterodactylus.fcp.highlevel;
21
22 import java.io.IOException;
23 import java.net.InetAddress;
24 import java.net.UnknownHostException;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import net.pterodactylus.fcp.AllData;
30 import net.pterodactylus.fcp.ClientHello;
31 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
32 import net.pterodactylus.fcp.ConfigData;
33 import net.pterodactylus.fcp.DataFound;
34 import net.pterodactylus.fcp.EndListPeerNotes;
35 import net.pterodactylus.fcp.EndListPeers;
36 import net.pterodactylus.fcp.EndListPersistentRequests;
37 import net.pterodactylus.fcp.FCPPluginReply;
38 import net.pterodactylus.fcp.FcpConnection;
39 import net.pterodactylus.fcp.FcpListener;
40 import net.pterodactylus.fcp.FcpMessage;
41 import net.pterodactylus.fcp.FinishedCompression;
42 import net.pterodactylus.fcp.GenerateSSK;
43 import net.pterodactylus.fcp.GetFailed;
44 import net.pterodactylus.fcp.IdentifierCollision;
45 import net.pterodactylus.fcp.NodeData;
46 import net.pterodactylus.fcp.NodeHello;
47 import net.pterodactylus.fcp.Peer;
48 import net.pterodactylus.fcp.PeerNote;
49 import net.pterodactylus.fcp.PeerRemoved;
50 import net.pterodactylus.fcp.PersistentGet;
51 import net.pterodactylus.fcp.PersistentPut;
52 import net.pterodactylus.fcp.PersistentPutDir;
53 import net.pterodactylus.fcp.PersistentRequestModified;
54 import net.pterodactylus.fcp.PersistentRequestRemoved;
55 import net.pterodactylus.fcp.PluginInfo;
56 import net.pterodactylus.fcp.ProtocolError;
57 import net.pterodactylus.fcp.PutFailed;
58 import net.pterodactylus.fcp.PutFetchable;
59 import net.pterodactylus.fcp.PutSuccessful;
60 import net.pterodactylus.fcp.SSKKeypair;
61 import net.pterodactylus.fcp.SimpleProgress;
62 import net.pterodactylus.fcp.StartedCompression;
63 import net.pterodactylus.fcp.SubscribedUSKUpdate;
64 import net.pterodactylus.fcp.TestDDAComplete;
65 import net.pterodactylus.fcp.TestDDAReply;
66 import net.pterodactylus.fcp.URIGenerated;
67 import net.pterodactylus.fcp.UnknownNodeIdentifier;
68 import net.pterodactylus.fcp.UnknownPeerNoteType;
69
70 /**
71  * A high-level client that allows simple yet full-featured access to a Freenet
72  * node.
73  * 
74  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
75  * @version $Id$
76  */
77 public class HighLevelClient {
78
79         /** Object for internal synchronization. */
80         private final Object syncObject = new Object();
81
82         /** The name of the client. */
83         private final String clientName;
84
85         /** The address of the node. */
86         private InetAddress address;
87
88         /** The port number of the node. */
89         private int port;
90
91         /** The FCP connection to the node. */
92         private FcpConnection fcpConnection;
93
94         /** The listener for the connection. */
95         private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
96
97         /** The callback for {@link #connect()}. */
98         private HighLevelCallback<ConnectResult> connectCallback;
99
100         /** Mapping from request identifiers to callbacks. */
101         private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
102
103         /**
104          * Creates a new high-level client that connects to a node on
105          * <code>localhost</code>.
106          * 
107          * @param clientName
108          *            The name of the client
109          * @throws UnknownHostException
110          *             if the hostname of the node can not be resolved.
111          */
112         public HighLevelClient(String clientName) throws UnknownHostException {
113                 this(clientName, "localhost");
114         }
115
116         /**
117          * Creates a new high-level client that connects to a node on the given
118          * host.
119          * 
120          * @param clientName
121          *            The name of the client
122          * @param host
123          *            The hostname of the node
124          * @throws UnknownHostException
125          *             if the hostname of the node can not be resolved.
126          */
127         public HighLevelClient(String clientName, String host) throws UnknownHostException {
128                 this(clientName, host, FcpConnection.DEFAULT_PORT);
129         }
130
131         /**
132          * Creates a new high-level client that connects to a node on the given
133          * host.
134          * 
135          * @param clientName
136          *            The name of the client
137          * @param host
138          *            The hostname of the node
139          * @param port
140          *            The port number of the node
141          * @throws UnknownHostException
142          *             if the hostname of the node can not be resolved.
143          */
144         public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
145                 this(clientName, InetAddress.getByName(host), port);
146         }
147
148         /**
149          * Creates a new high-level client that connects to a node at the given
150          * address.
151          * 
152          * @param clientName
153          *            The name of the client
154          * @param address
155          *            The address of the node
156          * @param port
157          *            The port number of the node
158          */
159         public HighLevelClient(String clientName, InetAddress address, int port) {
160                 this.clientName = clientName;
161                 this.address = address;
162                 this.port = port;
163         }
164
165         //
166         // ACCESSORS
167         //
168
169         //
170         // ACTIONS
171         //
172
173         /**
174          * Connects the client.
175          * 
176          * @return A callback with a connection result
177          * @throws IOException
178          *             if an I/O error occurs communicating with the node
179          */
180         public HighLevelCallback<ConnectResult> connect() throws IOException {
181                 fcpConnection = new FcpConnection(address, port);
182                 fcpConnection.addFcpListener(highLevelClientFcpListener);
183                 ClientHello clientHello = new ClientHello(clientName);
184                 connectCallback = new HighLevelCallback<ConnectResult>();
185                 fcpConnection.sendMessage(clientHello);
186                 return connectCallback;
187         }
188
189         /**
190          * Disconnects the client from the node.
191          */
192         public void disconnect() {
193         }
194
195         /**
196          * Generates a new SSK keypair.
197          * 
198          * @return A callback with the keypair
199          * @throws IOException
200          *             if an I/O error occurs communicating with the node
201          */
202         public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException {
203                 String identifier = generateIdentifier("generateSSK");
204                 GenerateSSK generateSSK = new GenerateSSK(identifier);
205                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>();
206                 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
207                 fcpConnection.sendMessage(generateSSK);
208                 return keyGenerationCallback;
209         }
210
211         /**
212          * Generates an identifier for the given function.
213          * 
214          * @param function
215          *            The name of the function
216          * @return An identifier
217          */
218         private String generateIdentifier(String function) {
219                 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
220         }
221
222         /**
223          * FCP listener for {@link HighLevelClient}.
224          * 
225          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
226          * @version $Id$
227          */
228         private class HighLevelClientFcpListener implements FcpListener {
229
230                 /**
231                  * Creates a new FCP listener for {@link HighLevelClient}.
232                  */
233                 HighLevelClientFcpListener() {
234                 }
235
236                 /**
237                  * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
238                  */
239                 public void connectionClosed(FcpConnection fcpConnection) {
240                 }
241
242                 /**
243                  * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
244                  *      net.pterodactylus.fcp.AllData)
245                  */
246                 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
247                 }
248
249                 /**
250                  * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
251                  *      net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
252                  */
253                 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
254                 }
255
256                 /**
257                  * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
258                  *      net.pterodactylus.fcp.ConfigData)
259                  */
260                 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
261                 }
262
263                 /**
264                  * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
265                  *      net.pterodactylus.fcp.DataFound)
266                  */
267                 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
268                 }
269
270                 /**
271                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
272                  *      net.pterodactylus.fcp.EndListPeerNotes)
273                  */
274                 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
275                 }
276
277                 /**
278                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
279                  *      net.pterodactylus.fcp.EndListPeers)
280                  */
281                 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
282                 }
283
284                 /**
285                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
286                  *      net.pterodactylus.fcp.EndListPersistentRequests)
287                  */
288                 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
289                 }
290
291                 /**
292                  * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
293                  *      net.pterodactylus.fcp.FCPPluginReply)
294                  */
295                 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
296                 }
297
298                 /**
299                  * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
300                  *      net.pterodactylus.fcp.GetFailed)
301                  */
302                 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
303                 }
304
305                 /**
306                  * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
307                  *      net.pterodactylus.fcp.IdentifierCollision)
308                  */
309                 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
310                 }
311
312                 /**
313                  * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
314                  *      net.pterodactylus.fcp.FcpMessage)
315                  */
316                 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
317                 }
318
319                 /**
320                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
321                  *      net.pterodactylus.fcp.NodeData)
322                  */
323                 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
324                 }
325
326                 /**
327                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
328                  *      net.pterodactylus.fcp.NodeHello)
329                  */
330                 @SuppressWarnings("synthetic-access")
331                 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
332                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
333                                 return;
334                         }
335                         ConnectResult connectResult = new ConnectResult();
336
337                         synchronized (syncObject) {
338                                 connectCallback.setResult(connectResult);
339                         }
340                         connectCallback = null;
341                 }
342
343                 /**
344                  * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
345                  *      net.pterodactylus.fcp.Peer)
346                  */
347                 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
348                 }
349
350                 /**
351                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
352                  *      net.pterodactylus.fcp.PeerNote)
353                  */
354                 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
355                 }
356
357                 /**
358                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
359                  *      net.pterodactylus.fcp.PeerRemoved)
360                  */
361                 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
362                 }
363
364                 /**
365                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
366                  *      net.pterodactylus.fcp.PersistentGet)
367                  */
368                 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
369                 }
370
371                 /**
372                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
373                  *      net.pterodactylus.fcp.PersistentPut)
374                  */
375                 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
376                 }
377
378                 /**
379                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
380                  *      net.pterodactylus.fcp.PersistentPutDir)
381                  */
382                 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
383                 }
384
385                 /**
386                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
387                  *      net.pterodactylus.fcp.PersistentRequestModified)
388                  */
389                 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
390                 }
391
392                 /**
393                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
394                  *      net.pterodactylus.fcp.PersistentRequestRemoved)
395                  */
396                 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
397                 }
398
399                 /**
400                  * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
401                  *      net.pterodactylus.fcp.PluginInfo)
402                  */
403                 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
404                 }
405
406                 /**
407                  * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
408                  *      net.pterodactylus.fcp.ProtocolError)
409                  */
410                 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
411                 }
412
413                 /**
414                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
415                  *      net.pterodactylus.fcp.PutFailed)
416                  */
417                 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
418                 }
419
420                 /**
421                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
422                  *      net.pterodactylus.fcp.PutFetchable)
423                  */
424                 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
425                 }
426
427                 /**
428                  * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
429                  *      net.pterodactylus.fcp.PutSuccessful)
430                  */
431                 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
432                 }
433
434                 /**
435                  * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
436                  *      net.pterodactylus.fcp.SSKKeypair)
437                  */
438                 @SuppressWarnings("synthetic-access")
439                 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
440                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
441                                 return;
442                         }
443                         HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
444                         if (keyGenerationCallback == null) {
445                                 return;
446                         }
447                         KeyGenerationResult keyGenerationResult = new KeyGenerationResult();
448                         keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
449                         keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
450                         keyGenerationCallback.setResult(keyGenerationResult);
451                 }
452
453                 /**
454                  * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
455                  *      net.pterodactylus.fcp.SimpleProgress)
456                  */
457                 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
458                 }
459
460                 /**
461                  * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
462                  *      net.pterodactylus.fcp.StartedCompression)
463                  */
464                 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
465                 }
466
467                 /**
468                  * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
469                  *      net.pterodactylus.fcp.SubscribedUSKUpdate)
470                  */
471                 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
472                 }
473
474                 /**
475                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
476                  *      net.pterodactylus.fcp.TestDDAComplete)
477                  */
478                 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
479                 }
480
481                 /**
482                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
483                  *      net.pterodactylus.fcp.TestDDAReply)
484                  */
485                 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
486                 }
487
488                 /**
489                  * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
490                  *      net.pterodactylus.fcp.URIGenerated)
491                  */
492                 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
493                 }
494
495                 /**
496                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
497                  *      net.pterodactylus.fcp.UnknownNodeIdentifier)
498                  */
499                 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
500                 }
501
502                 /**
503                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
504                  *      net.pterodactylus.fcp.UnknownPeerNoteType)
505                  */
506                 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
507                 }
508
509                 /**
510                  * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
511                  *      net.pterodactylus.fcp.FinishedCompression)
512                  */
513                 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {
514                 }
515
516         }
517
518 }