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>();
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>();
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>();
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 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
305 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
306 * net.pterodactylus.fcp.EndListPersistentRequests)
308 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
312 * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
313 * net.pterodactylus.fcp.FCPPluginReply)
315 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
319 * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
320 * net.pterodactylus.fcp.GetFailed)
322 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
326 * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
327 * net.pterodactylus.fcp.IdentifierCollision)
329 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
333 * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
334 * net.pterodactylus.fcp.FcpMessage)
336 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
340 * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
341 * net.pterodactylus.fcp.NodeData)
343 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
347 * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
348 * net.pterodactylus.fcp.NodeHello)
350 @SuppressWarnings("synthetic-access")
351 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
352 if (fcpConnection != HighLevelClient.this.fcpConnection) {
355 ConnectResult connectResult = new ConnectResult();
357 synchronized (syncObject) {
358 connectCallback.setResult(connectResult);
360 connectCallback = null;
364 * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
365 * net.pterodactylus.fcp.Peer)
367 @SuppressWarnings("synthetic-access")
368 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
369 if (fcpConnection != HighLevelClient.this.fcpConnection) {
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);
382 * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
383 * net.pterodactylus.fcp.PeerNote)
385 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
389 * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
390 * net.pterodactylus.fcp.PeerRemoved)
392 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
396 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
397 * net.pterodactylus.fcp.PersistentGet)
399 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
403 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
404 * net.pterodactylus.fcp.PersistentPut)
406 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
410 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
411 * net.pterodactylus.fcp.PersistentPutDir)
413 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
417 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
418 * net.pterodactylus.fcp.PersistentRequestModified)
420 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
424 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
425 * net.pterodactylus.fcp.PersistentRequestRemoved)
427 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
431 * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
432 * net.pterodactylus.fcp.PluginInfo)
434 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
438 * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
439 * net.pterodactylus.fcp.ProtocolError)
441 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
445 * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
446 * net.pterodactylus.fcp.PutFailed)
448 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
452 * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
453 * net.pterodactylus.fcp.PutFetchable)
455 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
459 * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
460 * net.pterodactylus.fcp.PutSuccessful)
462 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
466 * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
467 * net.pterodactylus.fcp.SSKKeypair)
469 @SuppressWarnings("synthetic-access")
470 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
471 if (fcpConnection != HighLevelClient.this.fcpConnection) {
474 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
475 if (keyGenerationCallback == null) {
478 KeyGenerationResult keyGenerationResult = new KeyGenerationResult();
479 keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
480 keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
481 keyGenerationCallback.setResult(keyGenerationResult);
485 * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
486 * net.pterodactylus.fcp.SimpleProgress)
488 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
492 * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
493 * net.pterodactylus.fcp.StartedCompression)
495 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
499 * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
500 * net.pterodactylus.fcp.SubscribedUSKUpdate)
502 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
506 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
507 * net.pterodactylus.fcp.TestDDAComplete)
509 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
513 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
514 * net.pterodactylus.fcp.TestDDAReply)
516 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
520 * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
521 * net.pterodactylus.fcp.URIGenerated)
523 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
527 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
528 * net.pterodactylus.fcp.UnknownNodeIdentifier)
530 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
534 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
535 * net.pterodactylus.fcp.UnknownPeerNoteType)
537 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
541 * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
542 * net.pterodactylus.fcp.FinishedCompression)
544 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {