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.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;
71 * A high-level client that allows simple yet full-featured access to a Freenet
74 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
77 public class HighLevelClient {
79 /** Object for internal synchronization. */
80 private final Object syncObject = new Object();
82 /** The name of the client. */
83 private final String clientName;
85 /** The address of the node. */
86 private InetAddress address;
88 /** The port number of the node. */
91 /** The FCP connection to the node. */
92 private FcpConnection fcpConnection;
94 /** The listener for the connection. */
95 private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
97 /** The callback for {@link #connect()}. */
98 private HighLevelCallback<ConnectResult> connectCallback;
100 /** Mapping from request identifiers to callbacks. */
101 private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
104 * Creates a new high-level client that connects to a node on
105 * <code>localhost</code>.
108 * The name of the client
109 * @throws UnknownHostException
110 * if the hostname of the node can not be resolved.
112 public HighLevelClient(String clientName) throws UnknownHostException {
113 this(clientName, "localhost");
117 * Creates a new high-level client that connects to a node on the given
121 * The name of the client
123 * The hostname of the node
124 * @throws UnknownHostException
125 * if the hostname of the node can not be resolved.
127 public HighLevelClient(String clientName, String host) throws UnknownHostException {
128 this(clientName, host, FcpConnection.DEFAULT_PORT);
132 * Creates a new high-level client that connects to a node on the given
136 * The name of the client
138 * The hostname of the node
140 * The port number of the node
141 * @throws UnknownHostException
142 * if the hostname of the node can not be resolved.
144 public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
145 this(clientName, InetAddress.getByName(host), port);
149 * Creates a new high-level client that connects to a node at the given
153 * The name of the client
155 * The address of the node
157 * The port number of the node
159 public HighLevelClient(String clientName, InetAddress address, int port) {
160 this.clientName = clientName;
161 this.address = address;
174 * Connects the client.
176 * @return A callback with a connection result
177 * @throws IOException
178 * if an I/O error occurs communicating with the node
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;
190 * Disconnects the client from the node.
192 public void disconnect() {
196 * Generates a new SSK keypair.
198 * @return A callback with the keypair
199 * @throws IOException
200 * if an I/O error occurs communicating with the node
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;
212 * Generates an identifier for the given function.
215 * The name of the function
216 * @return An identifier
218 private String generateIdentifier(String function) {
219 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
223 * FCP listener for {@link HighLevelClient}.
225 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
228 private class HighLevelClientFcpListener implements FcpListener {
231 * Creates a new FCP listener for {@link HighLevelClient}.
233 HighLevelClientFcpListener() {
237 * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
239 public void connectionClosed(FcpConnection fcpConnection) {
243 * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
244 * net.pterodactylus.fcp.AllData)
246 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
250 * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
251 * net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
253 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
257 * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
258 * net.pterodactylus.fcp.ConfigData)
260 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
264 * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
265 * net.pterodactylus.fcp.DataFound)
267 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
271 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
272 * net.pterodactylus.fcp.EndListPeerNotes)
274 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
278 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
279 * net.pterodactylus.fcp.EndListPeers)
281 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
285 * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
286 * net.pterodactylus.fcp.EndListPersistentRequests)
288 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
292 * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
293 * net.pterodactylus.fcp.FCPPluginReply)
295 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
299 * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
300 * net.pterodactylus.fcp.GetFailed)
302 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
306 * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
307 * net.pterodactylus.fcp.IdentifierCollision)
309 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
313 * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
314 * net.pterodactylus.fcp.FcpMessage)
316 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
320 * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
321 * net.pterodactylus.fcp.NodeData)
323 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
327 * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
328 * net.pterodactylus.fcp.NodeHello)
330 @SuppressWarnings("synthetic-access")
331 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
332 if (fcpConnection != HighLevelClient.this.fcpConnection) {
335 ConnectResult connectResult = new ConnectResult();
337 synchronized (syncObject) {
338 connectCallback.setResult(connectResult);
340 connectCallback = null;
344 * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
345 * net.pterodactylus.fcp.Peer)
347 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
351 * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
352 * net.pterodactylus.fcp.PeerNote)
354 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
358 * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
359 * net.pterodactylus.fcp.PeerRemoved)
361 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
365 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
366 * net.pterodactylus.fcp.PersistentGet)
368 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
372 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
373 * net.pterodactylus.fcp.PersistentPut)
375 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
379 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
380 * net.pterodactylus.fcp.PersistentPutDir)
382 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
386 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
387 * net.pterodactylus.fcp.PersistentRequestModified)
389 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
393 * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
394 * net.pterodactylus.fcp.PersistentRequestRemoved)
396 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
400 * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
401 * net.pterodactylus.fcp.PluginInfo)
403 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
407 * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
408 * net.pterodactylus.fcp.ProtocolError)
410 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
414 * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
415 * net.pterodactylus.fcp.PutFailed)
417 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
421 * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
422 * net.pterodactylus.fcp.PutFetchable)
424 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
428 * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
429 * net.pterodactylus.fcp.PutSuccessful)
431 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
435 * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
436 * net.pterodactylus.fcp.SSKKeypair)
438 @SuppressWarnings("synthetic-access")
439 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
440 if (fcpConnection != HighLevelClient.this.fcpConnection) {
443 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
444 if (keyGenerationCallback == null) {
447 KeyGenerationResult keyGenerationResult = new KeyGenerationResult();
448 keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
449 keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
450 keyGenerationCallback.setResult(keyGenerationResult);
454 * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
455 * net.pterodactylus.fcp.SimpleProgress)
457 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
461 * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
462 * net.pterodactylus.fcp.StartedCompression)
464 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
468 * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
469 * net.pterodactylus.fcp.SubscribedUSKUpdate)
471 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
475 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
476 * net.pterodactylus.fcp.TestDDAComplete)
478 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
482 * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
483 * net.pterodactylus.fcp.TestDDAReply)
485 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
489 * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
490 * net.pterodactylus.fcp.URIGenerated)
492 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
496 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
497 * net.pterodactylus.fcp.UnknownNodeIdentifier)
499 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
503 * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
504 * net.pterodactylus.fcp.UnknownPeerNoteType)
506 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
510 * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
511 * net.pterodactylus.fcp.FinishedCompression)
513 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {