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