remove warnings
[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.BufferedReader;
23 import java.io.File;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.net.InetAddress;
28 import java.net.URL;
29 import java.net.UnknownHostException;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.logging.Logger;
35
36 import net.pterodactylus.fcp.AddPeer;
37 import net.pterodactylus.fcp.AllData;
38 import net.pterodactylus.fcp.ClientGet;
39 import net.pterodactylus.fcp.ClientHello;
40 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
41 import net.pterodactylus.fcp.ConfigData;
42 import net.pterodactylus.fcp.DataFound;
43 import net.pterodactylus.fcp.EndListPeerNotes;
44 import net.pterodactylus.fcp.EndListPeers;
45 import net.pterodactylus.fcp.EndListPersistentRequests;
46 import net.pterodactylus.fcp.FCPPluginReply;
47 import net.pterodactylus.fcp.FcpConnection;
48 import net.pterodactylus.fcp.FcpListener;
49 import net.pterodactylus.fcp.FcpMessage;
50 import net.pterodactylus.fcp.FcpUtils;
51 import net.pterodactylus.fcp.FinishedCompression;
52 import net.pterodactylus.fcp.GenerateSSK;
53 import net.pterodactylus.fcp.GetFailed;
54 import net.pterodactylus.fcp.IdentifierCollision;
55 import net.pterodactylus.fcp.ListPeers;
56 import net.pterodactylus.fcp.NodeData;
57 import net.pterodactylus.fcp.NodeHello;
58 import net.pterodactylus.fcp.NodeRef;
59 import net.pterodactylus.fcp.Peer;
60 import net.pterodactylus.fcp.PeerNote;
61 import net.pterodactylus.fcp.PeerRemoved;
62 import net.pterodactylus.fcp.PersistentGet;
63 import net.pterodactylus.fcp.PersistentPut;
64 import net.pterodactylus.fcp.PersistentPutDir;
65 import net.pterodactylus.fcp.PersistentRequestModified;
66 import net.pterodactylus.fcp.PersistentRequestRemoved;
67 import net.pterodactylus.fcp.PluginInfo;
68 import net.pterodactylus.fcp.ProtocolError;
69 import net.pterodactylus.fcp.PutFailed;
70 import net.pterodactylus.fcp.PutFetchable;
71 import net.pterodactylus.fcp.PutSuccessful;
72 import net.pterodactylus.fcp.ReturnType;
73 import net.pterodactylus.fcp.SSKKeypair;
74 import net.pterodactylus.fcp.SimpleProgress;
75 import net.pterodactylus.fcp.StartedCompression;
76 import net.pterodactylus.fcp.SubscribedUSKUpdate;
77 import net.pterodactylus.fcp.TestDDAComplete;
78 import net.pterodactylus.fcp.TestDDAReply;
79 import net.pterodactylus.fcp.TestDDARequest;
80 import net.pterodactylus.fcp.TestDDAResponse;
81 import net.pterodactylus.fcp.URIGenerated;
82 import net.pterodactylus.fcp.UnknownNodeIdentifier;
83 import net.pterodactylus.fcp.UnknownPeerNoteType;
84
85 /**
86  * A high-level client that allows simple yet full-featured access to a Freenet
87  * node.
88  *
89  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
90  * @version $Id$
91  */
92 public class HighLevelClient {
93
94         /** Logger. */
95         private static final Logger logger = Logger.getLogger(HighLevelClient.class.getName());
96
97         /** Object for internal synchronization. */
98         private final Object syncObject = new Object();
99
100         /** The name of the client. */
101         private final String clientName;
102
103         /** The address of the node. */
104         private InetAddress address;
105
106         /** The port number of the node. */
107         private int port;
108
109         /** The FCP connection to the node. */
110         private FcpConnection fcpConnection;
111
112         /** The listener for the connection. */
113         private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
114
115         /** The callback for {@link #connect()}. */
116         private HighLevelCallback<ConnectResult> connectCallback;
117
118         /** Mapping from request identifiers to callbacks. */
119         private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
120
121         /** Mapping from request identifier to peer list callbacks. */
122         private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
123
124         /** Mapping from request identifier to peer callbacks. */
125         private Map<String, HighLevelCallback<PeerResult>> peerCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerResult>>());
126
127         /** Mapping from directories to DDA callbacks. */
128         private Map<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<DirectDiskAccessResult>>());
129
130         /** Mapping from request identifiers to download callbacks. */
131         private Map<String, HighLevelProgressCallback<DownloadResult>> downloadCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelProgressCallback<DownloadResult>>());
132
133         /**
134          * Creates a new high-level client that connects to a node on
135          * <code>localhost</code>.
136          *
137          * @param clientName
138          *            The name of the client
139          * @throws UnknownHostException
140          *             if the hostname of the node can not be resolved.
141          */
142         public HighLevelClient(String clientName) throws UnknownHostException {
143                 this(clientName, "localhost");
144         }
145
146         /**
147          * Creates a new high-level client that connects to a node on the given
148          * host.
149          *
150          * @param clientName
151          *            The name of the client
152          * @param host
153          *            The hostname of the node
154          * @throws UnknownHostException
155          *             if the hostname of the node can not be resolved.
156          */
157         public HighLevelClient(String clientName, String host) throws UnknownHostException {
158                 this(clientName, host, FcpConnection.DEFAULT_PORT);
159         }
160
161         /**
162          * Creates a new high-level client that connects to a node on the given
163          * host.
164          *
165          * @param clientName
166          *            The name of the client
167          * @param host
168          *            The hostname of the node
169          * @param port
170          *            The port number of the node
171          * @throws UnknownHostException
172          *             if the hostname of the node can not be resolved.
173          */
174         public HighLevelClient(String clientName, String host, int port) throws UnknownHostException {
175                 this(clientName, InetAddress.getByName(host), port);
176         }
177
178         /**
179          * Creates a new high-level client that connects to a node at the given
180          * address.
181          *
182          * @param clientName
183          *            The name of the client
184          * @param address
185          *            The address of the node
186          * @param port
187          *            The port number of the node
188          */
189         public HighLevelClient(String clientName, InetAddress address, int port) {
190                 this.clientName = clientName;
191                 this.address = address;
192                 this.port = port;
193         }
194
195         //
196         // ACCESSORS
197         //
198
199         //
200         // ACTIONS
201         //
202
203         /**
204          * Connects the client.
205          *
206          * @return A callback with a connection result
207          * @throws IOException
208          *             if an I/O error occurs communicating with the node
209          */
210         public HighLevelCallback<ConnectResult> connect() throws IOException {
211                 fcpConnection = new FcpConnection(address, port);
212                 fcpConnection.addFcpListener(highLevelClientFcpListener);
213                 ClientHello clientHello = new ClientHello(clientName);
214                 connectCallback = new HighLevelCallback<ConnectResult>(new ConnectResult());
215                 fcpConnection.sendMessage(clientHello);
216                 return connectCallback;
217         }
218
219         /**
220          * Disconnects the client from the node.
221          */
222         public void disconnect() {
223                 fcpConnection.disconnect();
224         }
225
226         /**
227          * Generates a new SSK keypair.
228          *
229          * @return A callback with the keypair
230          * @throws IOException
231          *             if an I/O error occurs communicating with the node
232          */
233         public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException {
234                 String identifier = generateIdentifier("generateSSK");
235                 GenerateSSK generateSSK = new GenerateSSK(identifier);
236                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>(new KeyGenerationResult(identifier));
237                 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
238                 fcpConnection.sendMessage(generateSSK);
239                 return keyGenerationCallback;
240         }
241
242         /**
243          * Gets a list of all peers from the node.
244          *
245          * @return A callback with the peer list
246          * @throws IOException
247          *             if an I/O error occurs with the node
248          */
249         public HighLevelCallback<PeerListResult> getPeers() throws IOException {
250                 String identifier = generateIdentifier("listPeers");
251                 ListPeers listPeers = new ListPeers(identifier, true, true);
252                 HighLevelCallback<PeerListResult> peerListCallback = new HighLevelCallback<PeerListResult>(new PeerListResult(identifier));
253                 peerListCallbacks.put(identifier, peerListCallback);
254                 fcpConnection.sendMessage(listPeers);
255                 return peerListCallback;
256         }
257
258         /**
259          * Adds the peer whose noderef is stored in the given file.
260          *
261          * @param nodeRefFile
262          *            The name of the file the peer’s noderef is stored in
263          * @return A peer callback
264          * @throws IOException
265          *             if an I/O error occurs communicating with the node
266          */
267         public HighLevelCallback<PeerResult> addPeer(String nodeRefFile) throws IOException {
268                 String identifier = generateIdentifier("addPeer");
269                 AddPeer addPeer = new AddPeer(nodeRefFile);
270                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
271                 peerCallbacks.put(identifier, peerCallback);
272                 fcpConnection.sendMessage(addPeer);
273                 return peerCallback;
274         }
275
276         /**
277          * Adds the peer whose noderef is stored in the given file.
278          *
279          * @param nodeRefURL
280          *            The URL where the peer’s noderef is stored
281          * @return A peer callback
282          * @throws IOException
283          *             if an I/O error occurs communicating with the node
284          */
285         public HighLevelCallback<PeerResult> addPeer(URL nodeRefURL) throws IOException {
286                 String identifier = generateIdentifier("addPeer");
287                 AddPeer addPeer = new AddPeer(nodeRefURL);
288                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
289                 peerCallbacks.put(identifier, peerCallback);
290                 fcpConnection.sendMessage(addPeer);
291                 return peerCallback;
292         }
293
294         /**
295          * Adds the peer whose noderef is stored in the given file.
296          *
297          * @param nodeRef
298          *            The peer’s noderef
299          * @return A peer callback
300          * @throws IOException
301          *             if an I/O error occurs communicating with the node
302          */
303         public HighLevelCallback<PeerResult> addPeer(NodeRef nodeRef) throws IOException {
304                 String identifier = generateIdentifier("addPeer");
305                 AddPeer addPeer = new AddPeer(nodeRef);
306                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
307                 peerCallbacks.put(identifier, peerCallback);
308                 fcpConnection.sendMessage(addPeer);
309                 return peerCallback;
310         }
311
312         /**
313          * Checks whether direct disk access for the given directory is possible.
314          * You have to perform this check before you can upload or download anything
315          * from or the disk directly!
316          *
317          * @param directory
318          *            The directory to check
319          * @param wantRead
320          *            Whether you want to read the given directory
321          * @param wantWrite
322          *            Whether you want to write to the given directory
323          * @return A direct disk access callback
324          * @throws IOException
325          */
326         public HighLevelCallback<DirectDiskAccessResult> checkDirectDiskAccess(String directory, boolean wantRead, boolean wantWrite) throws IOException {
327                 TestDDARequest testDDARequest = new TestDDARequest(directory, wantRead, wantWrite);
328                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = new HighLevelCallback<DirectDiskAccessResult>(new DirectDiskAccessResult(directory));
329                 directDiskAccessCallbacks.put(directory, directDiskAccessCallback);
330                 fcpConnection.sendMessage(testDDARequest);
331                 return directDiskAccessCallback;
332         }
333
334         /**
335          * Starts a download. Files can either be download to disk or streamed from
336          * the node. When downloading to disk you have to perform a direct disk
337          * access check for the directory you want to put the downloaded file in!
338          *
339          * @see #checkDirectDiskAccess(String, boolean, boolean)
340          * @param uri
341          *            The URI to get
342          * @param filename
343          *            The filename to save the data to, or <code>null</code> to
344          *            retrieve the data as InputStream from the
345          *            {@link DownloadResult}
346          * @param global
347          *            Whether to put the download on the global queue
348          * @return A download result
349          * @throws IOException
350          *             if an I/O error occurs communicating with the node
351          */
352         public HighLevelProgressCallback<DownloadResult> download(String uri, String filename, boolean global) throws IOException {
353                 String identifier = generateIdentifier("download");
354                 ClientGet clientGet = new ClientGet(uri, identifier, (filename == null) ? ReturnType.direct : ReturnType.disk);
355                 clientGet.setGlobal(global);
356                 HighLevelProgressCallback<DownloadResult> downloadCallback = new HighLevelProgressCallback<DownloadResult>(new DownloadResult(identifier));
357                 downloadCallbacks.put(identifier, downloadCallback);
358                 fcpConnection.sendMessage(clientGet);
359                 return downloadCallback;
360         }
361
362         //
363         // PRIVATE METHODS
364         //
365
366         /**
367          * Generates an identifier for the given function.
368          *
369          * @param function
370          *            The name of the function
371          * @return An identifier
372          */
373         private String generateIdentifier(String function) {
374                 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
375         }
376
377         /**
378          * FCP listener for {@link HighLevelClient}.
379          *
380          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
381          * @version $Id$
382          */
383         private class HighLevelClientFcpListener implements FcpListener {
384
385                 /** Mapping from directory to written file (for cleanup). */
386                 private final Map<DirectDiskAccessResult, String> writtenFiles = new HashMap<DirectDiskAccessResult, String>();
387
388                 /**
389                  * Creates a new FCP listener for {@link HighLevelClient}.
390                  */
391                 HighLevelClientFcpListener() {
392                         /* do nothing. */
393                 }
394
395                 //
396                 // PRIVATE METHODS
397                 //
398
399                 /**
400                  * Searches all callback collections for a callback with the given
401                  * identifier and cancels it.
402                  *
403                  * @param identifier
404                  *            The identifier to search for, or <code>null</code> to
405                  *            cancel all pending requests
406                  */
407                 @SuppressWarnings("synthetic-access")
408                 private void cancelIdentifier(String identifier) {
409                         synchronized (syncObject) {
410                                 if (connectCallback != null) {
411                                         connectCallback.getIntermediaryResult().setFailed(true);
412                                         connectCallback.setDone();
413                                         connectCallback = null;
414                                 }
415                         }
416                         if (identifier == null) {
417                                 /* key generation callbacks */
418                                 for (Entry<String, HighLevelCallback<KeyGenerationResult>> keyGenerationEntry: keyGenerationCallbacks.entrySet()) {
419                                         keyGenerationEntry.getValue().getIntermediaryResult().setFailed(true);
420                                         keyGenerationEntry.getValue().setDone();
421                                 }
422                                 keyGenerationCallbacks.clear();
423                                 /* peer list callbacks. */
424                                 for (Entry<String, HighLevelCallback<PeerListResult>> peerListEntry: peerListCallbacks.entrySet()) {
425                                         peerListEntry.getValue().getIntermediaryResult().setFailed(true);
426                                         peerListEntry.getValue().setDone();
427                                 }
428                                 peerListCallbacks.clear();
429                                 /* peer callbacks. */
430                                 for (Entry<String, HighLevelCallback<PeerResult>> peerEntry: peerCallbacks.entrySet()) {
431                                         peerEntry.getValue().getIntermediaryResult().setFailed(true);
432                                         peerEntry.getValue().setDone();
433                                 }
434                                 peerCallbacks.clear();
435                                 /* direct disk access callbacks. */
436                                 for (Entry<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessEntry: directDiskAccessCallbacks.entrySet()) {
437                                         directDiskAccessEntry.getValue().getIntermediaryResult().setFailed(true);
438                                         directDiskAccessEntry.getValue().setDone();
439                                 }
440                                 directDiskAccessCallbacks.clear();
441                                 /* download callbacks. */
442                                 for (Entry<String, HighLevelProgressCallback<DownloadResult>> downloadEntry: downloadCallbacks.entrySet()) {
443                                         downloadEntry.getValue().getIntermediaryResult().setFailed(true);
444                                         downloadEntry.getValue().setDone();
445                                 }
446                                 downloadCallbacks.clear();
447                         } else {
448                                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
449                                 if (keyGenerationCallback != null) {
450                                         keyGenerationCallback.getIntermediaryResult().setFailed(true);
451                                         keyGenerationCallback.setDone();
452                                         return;
453                                 }
454                                 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
455                                 if (peerListCallback != null) {
456                                         peerListCallback.getIntermediaryResult().setFailed(true);
457                                         peerListCallback.setDone();
458                                         return;
459                                 }
460                                 HighLevelCallback<PeerResult> peerCallback = peerCallbacks.remove(identifier);
461                                 if (peerCallback != null) {
462                                         peerCallback.getIntermediaryResult().setFailed(true);
463                                         peerCallback.setDone();
464                                         return;
465                                 }
466                                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(identifier);
467                                 if (directDiskAccessCallback != null) {
468                                         directDiskAccessCallback.getIntermediaryResult().setFailed(true);
469                                         directDiskAccessCallback.setDone();
470                                         return;
471                                 }
472                                 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
473                                 if (downloadCallback != null) {
474                                         downloadCallback.getIntermediaryResult().setFailed(true);
475                                         downloadCallback.setDone();
476                                         return;
477                                 }
478                         }
479                 }
480
481                 /**
482                  * Reads the given file and returns the first line of the file.
483                  *
484                  * @param readFilename
485                  *            The name of the file to read
486                  * @return The content of the file
487                  */
488                 private String readContent(String readFilename) {
489                         FileReader fileReader = null;
490                         BufferedReader bufferedFileReader = null;
491                         try {
492                                 fileReader = new FileReader(readFilename);
493                                 bufferedFileReader = new BufferedReader(fileReader);
494                                 String content = bufferedFileReader.readLine();
495                                 return content;
496                         } catch (IOException ioe1) {
497                                 /* swallow. */
498                         } finally {
499                                 FcpUtils.close(bufferedFileReader);
500                                 FcpUtils.close(fileReader);
501                         }
502                         return null;
503                 }
504
505                 /**
506                  * Writes the given content to the given file.
507                  *
508                  * @param directDiskAccessResult
509                  *            The DDA result
510                  * @param writeFilename
511                  *            The name of the file to write to
512                  * @param writeContent
513                  *            The content to write to the file
514                  */
515                 private void writeContent(DirectDiskAccessResult directDiskAccessResult, String writeFilename, String writeContent) {
516                         if ((writeFilename == null) || (writeContent == null)) {
517                                 return;
518                         }
519                         writtenFiles.put(directDiskAccessResult, writeFilename);
520                         FileWriter fileWriter = null;
521                         try {
522                                 fileWriter = new FileWriter(writeFilename);
523                                 fileWriter.write(writeContent);
524                         } catch (IOException ioe1) {
525                                 /* swallow. */
526                         } finally {
527                                 FcpUtils.close(fileWriter);
528                         }
529                 }
530
531                 /**
532                  * Cleans up any files that written for the given result.
533                  *
534                  * @param directDiskAccessResult
535                  *            The direct disk access result
536                  */
537                 @SuppressWarnings("synthetic-access")
538                 private void cleanFiles(DirectDiskAccessResult directDiskAccessResult) {
539                         String writeFilename = writtenFiles.remove(directDiskAccessResult);
540                         if (writeFilename != null) {
541                                 if (!new File(writeFilename).delete()) {
542                                         logger.warning("could not delete " + writeFilename);
543                                 }
544                         }
545                 }
546
547                 //
548                 // INTERFACE FcpListener
549                 //
550
551                 /**
552                  * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
553                  */
554                 @SuppressWarnings("synthetic-access")
555                 public void connectionClosed(FcpConnection fcpConnection) {
556                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
557                                 return;
558                         }
559                         cancelIdentifier(null);
560                 }
561
562                 /**
563                  * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
564                  *      net.pterodactylus.fcp.AllData)
565                  */
566                 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
567                         /* TODO */
568                 }
569
570                 /**
571                  * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
572                  *      net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
573                  */
574                 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
575                         /* TODO */
576                 }
577
578                 /**
579                  * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
580                  *      net.pterodactylus.fcp.ConfigData)
581                  */
582                 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
583                         /* TODO */
584                 }
585
586                 /**
587                  * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
588                  *      net.pterodactylus.fcp.DataFound)
589                  */
590                 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
591                         /* TODO */
592                 }
593
594                 /**
595                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
596                  *      net.pterodactylus.fcp.EndListPeerNotes)
597                  */
598                 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
599                         /* TODO */
600                 }
601
602                 /**
603                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
604                  *      net.pterodactylus.fcp.EndListPeers)
605                  */
606                 @SuppressWarnings("synthetic-access")
607                 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
608                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
609                                 return;
610                         }
611                         String identifier = endListPeers.getIdentifier();
612                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
613                         if (peerListCallback == null) {
614                                 return;
615                         }
616                         peerListCallback.setDone();
617                 }
618
619                 /**
620                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
621                  *      net.pterodactylus.fcp.EndListPersistentRequests)
622                  */
623                 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
624                         /* TODO */
625                 }
626
627                 /**
628                  * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
629                  *      net.pterodactylus.fcp.FCPPluginReply)
630                  */
631                 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
632                         /* TODO */
633                 }
634
635                 /**
636                  * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
637                  *      net.pterodactylus.fcp.GetFailed)
638                  */
639                 @SuppressWarnings("synthetic-access")
640                 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
641                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
642                                 return;
643                         }
644                         String identifier = getFailed.getIdentifier();
645                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
646                         if (downloadCallback != null) {
647                                 downloadCallback.getIntermediaryResult().setFailed(true);
648                                 downloadCallback.setDone();
649                                 return;
650                         }
651                         /* unknown identifier? */
652                         logger.warning("unknown identifier for GetFailed: " + identifier);
653                 }
654
655                 /**
656                  * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
657                  *      net.pterodactylus.fcp.IdentifierCollision)
658                  */
659                 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
660                         /* TODO */
661                 }
662
663                 /**
664                  * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
665                  *      net.pterodactylus.fcp.FcpMessage)
666                  */
667                 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
668                         /* TODO */
669                 }
670
671                 /**
672                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
673                  *      net.pterodactylus.fcp.NodeData)
674                  */
675                 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
676                         /* TODO */
677                 }
678
679                 /**
680                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
681                  *      net.pterodactylus.fcp.NodeHello)
682                  */
683                 @SuppressWarnings("synthetic-access")
684                 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
685                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
686                                 return;
687                         }
688                         synchronized (syncObject) {
689                                 connectCallback.getIntermediaryResult().setFailed(false);
690                                 connectCallback.setDone();
691                                 connectCallback = null;
692                         }
693                 }
694
695                 /**
696                  * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
697                  *      net.pterodactylus.fcp.Peer)
698                  */
699                 @SuppressWarnings("synthetic-access")
700                 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
701                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
702                                 return;
703                         }
704                         String identifier = peer.getIdentifier();
705                         if (identifier == null) {
706                                 return;
707                         }
708                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
709                         if (peerListCallback != null) {
710                                 peerListCallback.getIntermediaryResult().addPeer(peer);
711                                 return;
712                         }
713                         HighLevelCallback<PeerResult> peerResult = peerCallbacks.remove(identifier);
714                         if (peerResult != null) {
715                                 peerResult.getIntermediaryResult().setPeer(peer);
716                                 peerResult.setDone();
717                                 return;
718                         }
719                         logger.warning("got Peer message with unknown identifier: " + identifier);
720                 }
721
722                 /**
723                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
724                  *      net.pterodactylus.fcp.PeerNote)
725                  */
726                 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
727                         /* TODO */
728                 }
729
730                 /**
731                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
732                  *      net.pterodactylus.fcp.PeerRemoved)
733                  */
734                 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
735                         /* TODO */
736                 }
737
738                 /**
739                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
740                  *      net.pterodactylus.fcp.PersistentGet)
741                  */
742                 @SuppressWarnings("synthetic-access")
743                 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
744                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
745                                 return;
746                         }
747                         String identifier = persistentGet.getIdentifier();
748                         if (downloadCallbacks.containsKey(identifier)) {
749                                 /* ignore, because a download does not care about this. */
750                                 return;
751                         }
752                 }
753
754                 /**
755                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
756                  *      net.pterodactylus.fcp.PersistentPut)
757                  */
758                 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
759                         /* TODO */
760                 }
761
762                 /**
763                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
764                  *      net.pterodactylus.fcp.PersistentPutDir)
765                  */
766                 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
767                         /* TODO */
768                 }
769
770                 /**
771                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
772                  *      net.pterodactylus.fcp.PersistentRequestModified)
773                  */
774                 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
775                         /* TODO */
776                 }
777
778                 /**
779                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
780                  *      net.pterodactylus.fcp.PersistentRequestRemoved)
781                  */
782                 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
783                         /* TODO */
784                 }
785
786                 /**
787                  * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
788                  *      net.pterodactylus.fcp.PluginInfo)
789                  */
790                 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
791                         /* TODO */
792                 }
793
794                 /**
795                  * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
796                  *      net.pterodactylus.fcp.ProtocolError)
797                  */
798                 @SuppressWarnings("synthetic-access")
799                 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
800                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
801                                 return;
802                         }
803                         String identifier = protocolError.getIdentifier();
804                         if (identifier == null) {
805                                 return;
806                         }
807                         cancelIdentifier(identifier);
808                 }
809
810                 /**
811                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
812                  *      net.pterodactylus.fcp.PutFailed)
813                  */
814                 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
815                         /* TODO */
816                 }
817
818                 /**
819                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
820                  *      net.pterodactylus.fcp.PutFetchable)
821                  */
822                 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
823                         /* TODO */
824                 }
825
826                 /**
827                  * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
828                  *      net.pterodactylus.fcp.PutSuccessful)
829                  */
830                 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
831                         /* TODO */
832                 }
833
834                 /**
835                  * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
836                  *      net.pterodactylus.fcp.SSKKeypair)
837                  */
838                 @SuppressWarnings("synthetic-access")
839                 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
840                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
841                                 return;
842                         }
843                         HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
844                         if (keyGenerationCallback == null) {
845                                 return;
846                         }
847                         KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
848                         keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
849                         keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
850                         keyGenerationCallback.setDone();
851                 }
852
853                 /**
854                  * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
855                  *      net.pterodactylus.fcp.SimpleProgress)
856                  */
857                 @SuppressWarnings("synthetic-access")
858                 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
859                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
860                                 return;
861                         }
862                         String identifier = simpleProgress.getIdentifier();
863                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
864                         if (downloadCallback != null) {
865                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
866                                 downloadResult.setTotalBlocks(simpleProgress.getTotal());
867                                 downloadResult.setRequiredBlocks(simpleProgress.getRequired());
868                                 downloadResult.setSuccessfulBlocks(simpleProgress.getSucceeded());
869                                 downloadResult.setFailedBlocks(simpleProgress.getFailed());
870                                 downloadResult.setFatallyFailedBlocks(simpleProgress.getFatallyFailed());
871                                 downloadResult.setTotalFinalized(simpleProgress.isFinalizedTotal());
872                                 downloadCallback.progressUpdated();
873                                 return;
874                         }
875                         /* unknown identifier? */
876                         logger.warning("unknown identifier for SimpleProgress: " + identifier);
877                 }
878
879                 /**
880                  * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
881                  *      net.pterodactylus.fcp.StartedCompression)
882                  */
883                 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
884                         /* TODO */
885                 }
886
887                 /**
888                  * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
889                  *      net.pterodactylus.fcp.SubscribedUSKUpdate)
890                  */
891                 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
892                         /* TODO */
893                 }
894
895                 /**
896                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
897                  *      net.pterodactylus.fcp.TestDDAComplete)
898                  */
899                 @SuppressWarnings("synthetic-access")
900                 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
901                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
902                                 return;
903                         }
904                         String directory = testDDAComplete.getDirectory();
905                         if (directory == null) {
906                                 return;
907                         }
908                         HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(directory);
909                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallback.getIntermediaryResult();
910                         cleanFiles(directDiskAccessResult);
911                         directDiskAccessResult.setReadAllowed(testDDAComplete.isReadDirectoryAllowed());
912                         directDiskAccessResult.setWriteAllowed(testDDAComplete.isWriteDirectoryAllowed());
913                         directDiskAccessCallback.setDone();
914                 }
915
916                 /**
917                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
918                  *      net.pterodactylus.fcp.TestDDAReply)
919                  */
920                 @SuppressWarnings("synthetic-access")
921                 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
922                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
923                                 return;
924                         }
925                         String directory = testDDAReply.getDirectory();
926                         if (directory == null) {
927                                 return;
928                         }
929                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallbacks.get(directory).getIntermediaryResult();
930                         String readFilename = testDDAReply.getReadFilename();
931                         String readContent = readContent(readFilename);
932                         String writeFilename = testDDAReply.getWriteFilename();
933                         String writeContent = testDDAReply.getContentToWrite();
934                         writeContent(directDiskAccessResult, writeFilename, writeContent);
935                         TestDDAResponse testDDAResponse = new TestDDAResponse(directory, readContent);
936                         try {
937                                 fcpConnection.sendMessage(testDDAResponse);
938                         } catch (IOException e) {
939                                 /* swallow. I’m verry unhappy about this. */
940                         }
941                 }
942
943                 /**
944                  * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
945                  *      net.pterodactylus.fcp.URIGenerated)
946                  */
947                 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
948                         /* TODO */
949                 }
950
951                 /**
952                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
953                  *      net.pterodactylus.fcp.UnknownNodeIdentifier)
954                  */
955                 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
956                         /* TODO */
957                 }
958
959                 /**
960                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
961                  *      net.pterodactylus.fcp.UnknownPeerNoteType)
962                  */
963                 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
964                         /* TODO */
965                 }
966
967                 /**
968                  * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
969                  *      net.pterodactylus.fcp.FinishedCompression)
970                  */
971                 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {
972                         /* TODO */
973                 }
974
975         }
976
977 }