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