2 * fcplib - HighLevelClient.java -
3 * Copyright © 2008 David Roden
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.
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.
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.
20 package net.pterodactylus.fcp.highlevel;
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;
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;
72 * A high-level client that allows simple yet full-featured access to a Freenet
75 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
78 public class HighLevelClient {
80 /** Object for internal synchronization. */
81 private final Object syncObject = new Object();
83 /** The name of the client. */
84 private final String clientName;
86 /** The address of the node. */
87 private InetAddress address;
89 /** The port number of the node. */
92 /** The FCP connection to the node. */
93 private FcpConnection fcpConnection;
95 /** The listener for the connection. */
96 private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
98 /** The callback for {@link #connect()}. */
99 private HighLevelCallback<ConnectResult> connectCallback;
101 /** Mapping from request identifiers to callbacks. */
102 private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
104 /** Mapping from request identifier to peer list callbacks. */
105 private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
108 * Creates a new high-level client that connects to a node on
109 * <code>localhost</code>.
112 * The name of the client
113 * @throws UnknownHostException
114 * if the hostname of the node can not be resolved.
116 public HighLevelClient(String clientName) throws UnknownHostException {
117 this(clientName, "localhost");
121 * Creates a new high-level client that connects to a node on the given
125 * The name of the client
127 * The hostname of the node
128 * @throws UnknownHostException
129 * if the hostname of the node can not be resolved.
131 public HighLevelClient(String clientName, String host) throws UnknownHostException {
132 this(clientName, host, FcpConnection.DEFAULT_PORT);
136 * Creates a new high-level client that connects to a node on the given
140 * The name of the client
142 * The hostname of the node
144 * The port number of the node
145 * @throws UnknownHostException
146 * if the hostname of the node can not be resolved.
148 public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
149 this(clientName, InetAddress.getByName(host), port);
153 * Creates a new high-level client that connects to a node at the given
157 * The name of the client
159 * The address of the node
161 * The port number of the node
163 public HighLevelClient(String clientName, InetAddress address, int port) {
164 this.clientName = clientName;
165 this.address = address;
178 * Connects the client.
180 * @return A callback with a connection result
181 * @throws IOException
182 * if an I/O error occurs communicating with the node
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>(new ConnectResult());
189 fcpConnection.sendMessage(clientHello);
190 return connectCallback;
194 * Disconnects the client from the node.
196 public void disconnect() {
200 * Generates a new SSK keypair.
202 * @return A callback with the keypair
203 * @throws IOException
204 * if an I/O error occurs communicating with the node
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>(new KeyGenerationResult());
210 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
211 fcpConnection.sendMessage(generateSSK);
212 return keyGenerationCallback;
216 * Gets a list of all peers from the node.
218 * @return A callback with the peer list
219 * @throws IOException
220 * if an I/O error occurs with the node
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>(new PeerListResult());
226 peerListCallbacks.put(identifier, peerListCallback);
227 fcpConnection.sendMessage(listPeers);
228 return peerListCallback;
232 * Generates an identifier for the given function.
235 * The name of the function
236 * @return An identifier
238 private String generateIdentifier(String function) {
239 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
243 * FCP listener for {@link HighLevelClient}.
245 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
248 private class HighLevelClientFcpListener implements FcpListener {
251 * Creates a new FCP listener for {@link HighLevelClient}.
253 HighLevelClientFcpListener() {
257 * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
259 public void connectionClosed(FcpConnection fcpConnection) {
263 * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
264 * net.pterodactylus.fcp.AllData)
266 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
270 * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
271 * net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
273 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
277 * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
278 * net.pterodactylus.fcp.ConfigData)
280 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
284 * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
285 * net.pterodactylus.fcp.DataFound)
287 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
291 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
292 * net.pterodactylus.fcp.EndListPeerNotes)
294 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
298 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
299 * net.pterodactylus.fcp.EndListPeers)
301 @SuppressWarnings("synthetic-access")
302 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
303 if (fcpConnection != HighLevelClient.this.fcpConnection) {
306 String identifier = endListPeers.getIdentifier();
307 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
308 if (peerListCallback == null) {
311 peerListCallback.setDone();
315 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
316 * net.pterodactylus.fcp.EndListPersistentRequests)
318 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
322 * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
323 * net.pterodactylus.fcp.FCPPluginReply)
325 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
329 * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
330 * net.pterodactylus.fcp.GetFailed)
332 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
336 * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
337 * net.pterodactylus.fcp.IdentifierCollision)
339 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
343 * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
344 * net.pterodactylus.fcp.FcpMessage)
346 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
350 * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
351 * net.pterodactylus.fcp.NodeData)
353 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
357 * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
358 * net.pterodactylus.fcp.NodeHello)
360 @SuppressWarnings("synthetic-access")
361 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
362 if (fcpConnection != HighLevelClient.this.fcpConnection) {
365 synchronized (syncObject) {
366 connectCallback.getIntermediaryResult().setFailed(false);
367 connectCallback.setDone();
368 connectCallback = null;
373 * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
374 * net.pterodactylus.fcp.Peer)
376 @SuppressWarnings("synthetic-access")
377 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
378 if (fcpConnection != HighLevelClient.this.fcpConnection) {
381 String identifier = peer.getIdentifier();
382 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
383 if (peerListCallback == null) {
386 peerListCallback.getIntermediaryResult().addPeer(peer);
390 * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
391 * net.pterodactylus.fcp.PeerNote)
393 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
397 * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
398 * net.pterodactylus.fcp.PeerRemoved)
400 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
404 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
405 * net.pterodactylus.fcp.PersistentGet)
407 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
411 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
412 * net.pterodactylus.fcp.PersistentPut)
414 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
418 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
419 * net.pterodactylus.fcp.PersistentPutDir)
421 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
425 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
426 * net.pterodactylus.fcp.PersistentRequestModified)
428 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
432 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
433 * net.pterodactylus.fcp.PersistentRequestRemoved)
435 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
439 * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
440 * net.pterodactylus.fcp.PluginInfo)
442 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
446 * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
447 * net.pterodactylus.fcp.ProtocolError)
449 @SuppressWarnings("synthetic-access")
450 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
451 if (fcpConnection != HighLevelClient.this.fcpConnection) {
454 String identifier = protocolError.getIdentifier();
455 if (identifier == null) {
458 /* now check all callbacks. */
459 synchronized (syncObject) {
460 if (connectCallback != null) {
461 connectCallback.getIntermediaryResult().setFailed(true);
462 connectCallback.setDone();
463 connectCallback = null;
466 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
467 if (keyGenerationCallback != null) {
468 keyGenerationCallback.getIntermediaryResult().setFailed(true);
469 keyGenerationCallback.setDone();
474 * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
475 * net.pterodactylus.fcp.PutFailed)
477 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
481 * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
482 * net.pterodactylus.fcp.PutFetchable)
484 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
488 * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
489 * net.pterodactylus.fcp.PutSuccessful)
491 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
495 * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
496 * net.pterodactylus.fcp.SSKKeypair)
498 @SuppressWarnings("synthetic-access")
499 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
500 if (fcpConnection != HighLevelClient.this.fcpConnection) {
503 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
504 if (keyGenerationCallback == null) {
507 KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
508 keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
509 keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
510 keyGenerationCallback.setDone();
514 * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
515 * net.pterodactylus.fcp.SimpleProgress)
517 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
521 * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
522 * net.pterodactylus.fcp.StartedCompression)
524 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
528 * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
529 * net.pterodactylus.fcp.SubscribedUSKUpdate)
531 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
535 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
536 * net.pterodactylus.fcp.TestDDAComplete)
538 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
542 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
543 * net.pterodactylus.fcp.TestDDAReply)
545 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
549 * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
550 * net.pterodactylus.fcp.URIGenerated)
552 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
556 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
557 * net.pterodactylus.fcp.UnknownNodeIdentifier)
559 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
563 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
564 * net.pterodactylus.fcp.UnknownPeerNoteType)
566 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
570 * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
571 * net.pterodactylus.fcp.FinishedCompression)
573 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {