231d383339fb939ebe8224f7c94ad25aed4568f3
[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.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Map.Entry;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
38
39 import net.pterodactylus.fcp.AddPeer;
40 import net.pterodactylus.fcp.AllData;
41 import net.pterodactylus.fcp.ClientGet;
42 import net.pterodactylus.fcp.ClientHello;
43 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
44 import net.pterodactylus.fcp.ConfigData;
45 import net.pterodactylus.fcp.DataFound;
46 import net.pterodactylus.fcp.EndListPeerNotes;
47 import net.pterodactylus.fcp.EndListPeers;
48 import net.pterodactylus.fcp.EndListPersistentRequests;
49 import net.pterodactylus.fcp.FCPPluginReply;
50 import net.pterodactylus.fcp.FcpConnection;
51 import net.pterodactylus.fcp.FcpListener;
52 import net.pterodactylus.fcp.FcpMessage;
53 import net.pterodactylus.fcp.FcpUtils;
54 import net.pterodactylus.fcp.FinishedCompression;
55 import net.pterodactylus.fcp.GenerateSSK;
56 import net.pterodactylus.fcp.GetFailed;
57 import net.pterodactylus.fcp.IdentifierCollision;
58 import net.pterodactylus.fcp.ListPeers;
59 import net.pterodactylus.fcp.ListPersistentRequests;
60 import net.pterodactylus.fcp.NodeData;
61 import net.pterodactylus.fcp.NodeHello;
62 import net.pterodactylus.fcp.NodeRef;
63 import net.pterodactylus.fcp.Peer;
64 import net.pterodactylus.fcp.PeerNote;
65 import net.pterodactylus.fcp.PeerRemoved;
66 import net.pterodactylus.fcp.PersistentGet;
67 import net.pterodactylus.fcp.PersistentPut;
68 import net.pterodactylus.fcp.PersistentPutDir;
69 import net.pterodactylus.fcp.PersistentRequestModified;
70 import net.pterodactylus.fcp.PersistentRequestRemoved;
71 import net.pterodactylus.fcp.PluginInfo;
72 import net.pterodactylus.fcp.ProtocolError;
73 import net.pterodactylus.fcp.PutFailed;
74 import net.pterodactylus.fcp.PutFetchable;
75 import net.pterodactylus.fcp.PutSuccessful;
76 import net.pterodactylus.fcp.ReturnType;
77 import net.pterodactylus.fcp.SSKKeypair;
78 import net.pterodactylus.fcp.SimpleProgress;
79 import net.pterodactylus.fcp.StartedCompression;
80 import net.pterodactylus.fcp.SubscribedUSKUpdate;
81 import net.pterodactylus.fcp.TestDDAComplete;
82 import net.pterodactylus.fcp.TestDDAReply;
83 import net.pterodactylus.fcp.TestDDARequest;
84 import net.pterodactylus.fcp.TestDDAResponse;
85 import net.pterodactylus.fcp.URIGenerated;
86 import net.pterodactylus.fcp.UnknownNodeIdentifier;
87 import net.pterodactylus.fcp.UnknownPeerNoteType;
88 import net.pterodactylus.fcp.WatchGlobal;
89
90 /**
91  * A high-level client that allows simple yet full-featured access to a Freenet
92  * node.
93  *
94  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
95  */
96 public class HighLevelClient {
97
98         /** Logger. */
99         private static final Logger logger = Logger.getLogger(HighLevelClient.class.getName());
100
101         /** Object for internal synchronization. */
102         private final Object syncObject = new Object();
103
104         /** The name of the client. */
105         private final String clientName;
106
107         /** The FCP connection to the node. */
108         private FcpConnection fcpConnection = null;
109
110         /** Listeners for high-level client events. */
111         private List<HighLevelClientListener> highLevelClientListeners = Collections.synchronizedList(new ArrayList<HighLevelClientListener>());
112
113         /** The listener for the connection. */
114         private HighLevelClientFcpListener highLevelClientFcpListener = new HighLevelClientFcpListener();
115
116         /** The listeners for progress events. */
117         private List<HighLevelProgressListener> highLevelProgressListeners = Collections.synchronizedList(new ArrayList<HighLevelProgressListener>());
118
119         /** The callback for {@link #connect(String)}. */
120         private HighLevelCallback<ConnectResult> connectCallback;
121
122         /** Mapping from request identifiers to callbacks. */
123         private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
124
125         /** Mapping from request identifier to peer list callbacks. */
126         private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
127
128         /** Mapping from request identifier to peer callbacks. */
129         private Map<String, HighLevelCallback<PeerResult>> peerCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerResult>>());
130
131         /** Mapping from directories to DDA callbacks. */
132         private Map<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<DirectDiskAccessResult>>());
133
134         /** Mapping from request identifiers to download callbacks. */
135         private Map<String, HighLevelProgressCallback<DownloadResult>> downloadCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelProgressCallback<DownloadResult>>());
136
137         /** The callback for {@link #getRequests()}. */
138         private HighLevelCallback<RequestListResult> requestListCallback;
139
140         /**
141          * Creates a new high-level client that connects to a node on
142          * <code>localhost</code>.
143          *
144          * @param clientName
145          *            The name of the client
146          */
147         public HighLevelClient(String clientName) {
148                 this.clientName = clientName;
149         }
150
151         //
152         // EVENT MANAGEMENT
153         //
154
155         /**
156          * Adds the given high-level client listener to list of listeners.
157          *
158          * @param highLevelClientListener
159          *            The listener to add
160          */
161         public void addHighLevelClientListener(HighLevelClientListener highLevelClientListener) {
162                 highLevelClientListeners.add(highLevelClientListener);
163         }
164
165         /**
166          * Removes the given high-level client listener from the list of listeners.
167          *
168          * @param highLevelClientListener
169          *            The listener to remove
170          */
171         public void removeHighLevelClientListener(HighLevelClientListener highLevelClientListener) {
172                 highLevelClientListeners.remove(highLevelClientListener);
173         }
174
175         /**
176          * Notifies all listeners that a client has connected.
177          */
178         private void fireClientConnected() {
179                 for (HighLevelClientListener highLevelClientListener : highLevelClientListeners) {
180                         highLevelClientListener.clientConnected(this);
181                 }
182         }
183
184         /**
185          * Notifies all listeners that a client has disconnected.
186          *
187          * @param throwable
188          *            The exception that caused the disconnect, or <code>null</code>
189          *            if there was no exception
190          */
191         private void fireClientDisconnected(Throwable throwable) {
192                 for (HighLevelClientListener highLevelClientListener : highLevelClientListeners) {
193                         highLevelClientListener.clientDisconnected(this, throwable);
194                 }
195         }
196
197         /**
198          * Adds a high-level progress listener.
199          *
200          * @param highLevelProgressListener
201          *            The high-level progress listener to add
202          */
203         public void addHighLevelProgressListener(HighLevelProgressListener highLevelProgressListener) {
204                 highLevelProgressListeners.add(highLevelProgressListener);
205         }
206
207         /**
208          * Removes a high-level progress listener.
209          *
210          * @param highLevelProgressListener
211          *            The high-level progress listener to remove
212          */
213         public void removeHighLevelProgressListener(HighLevelProgressListener highLevelProgressListener) {
214                 highLevelProgressListeners.remove(highLevelProgressListener);
215         }
216
217         /**
218          * Notifies all listeners that the request with the given identifier made
219          * some progress.
220          *
221          * @param identifier
222          *            The identifier of the request
223          * @param highLevelProgress
224          *            The progress of the request
225          */
226         private void fireProgressReceived(String identifier, HighLevelProgress highLevelProgress) {
227                 for (HighLevelProgressListener highLevelProgressListener : highLevelProgressListeners) {
228                         highLevelProgressListener.progressReceived(this, identifier, highLevelProgress);
229                 }
230         }
231
232         //
233         // ACCESSORS
234         //
235
236         /**
237          * Returns the FCP connection that backs this high-level client. This method
238          * should be used with care as fiddling around with the FCP connection can
239          * easily break the high-level client if you don’t know what you’re doing!
240          *
241          * @return The FCP connection of this client
242          */
243         public FcpConnection getFcpConnection() {
244                 return fcpConnection;
245         }
246
247         /**
248          * Returns whether the node is connected.
249          *
250          * @return <code>true</code> if the node is currently connected,
251          *         <code>false</code> otherwise
252          */
253         public boolean isConnected() {
254                 return fcpConnection != null;
255         }
256
257         //
258         // ACTIONS
259         //
260
261         /**
262          * Connects the client.
263          *
264          * @param hostname
265          *            The hostname of the node
266          * @return A callback with a connection result
267          * @throws UnknownHostException
268          *             if the hostname can not be resolved
269          * @throws IOException
270          *             if an I/O error occurs communicating with the node
271          */
272         public HighLevelCallback<ConnectResult> connect(String hostname) throws UnknownHostException, IOException {
273                 return connect(hostname, 9481);
274         }
275
276         /**
277          * Connects the client.
278          *
279          * @param hostname
280          *            The hostname of the node
281          * @param port
282          *            The port number of the node
283          * @return A callback with a connection result
284          * @throws UnknownHostException
285          *             if the hostname can not be resolved
286          * @throws IOException
287          *             if an I/O error occurs communicating with the node
288          */
289         public HighLevelCallback<ConnectResult> connect(String hostname, int port) throws UnknownHostException, IOException {
290                 return connect(InetAddress.getByName(hostname), port);
291         }
292
293         /**
294          * Connects the client.
295          *
296          * @param address
297          *            The address of the node
298          * @param port
299          *            The port number of the node
300          * @return A callback with a connection result
301          * @throws IOException
302          *             if an I/O error occurs communicating with the node
303          */
304         public HighLevelCallback<ConnectResult> connect(InetAddress address, int port) throws IOException {
305                 try {
306                         synchronized (this) {
307                                 fcpConnection = new FcpConnection(address, port);
308                         }
309                         fcpConnection.addFcpListener(highLevelClientFcpListener);
310                         fcpConnection.connect();
311                         ClientHello clientHello = new ClientHello(clientName);
312                         connectCallback = new HighLevelCallback<ConnectResult>(new ConnectResult());
313                         fcpConnection.sendMessage(clientHello);
314                         return connectCallback;
315                 } catch (IOException ioe1) {
316                         fcpConnection = null;
317                         throw ioe1;
318                 }
319         }
320
321         /**
322          * Disconnects the client from the node.
323          */
324         public void disconnect() {
325                 disconnect(null);
326         }
327
328         /**
329          * Generates a new SSK keypair.
330          *
331          * @return A callback with the keypair
332          * @throws IOException
333          *             if an I/O error occurs communicating with the node
334          * @throws HighLevelException
335          *             if the client is not connected
336          */
337         public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException, HighLevelException {
338                 checkConnection();
339                 String identifier = generateIdentifier("generateSSK");
340                 GenerateSSK generateSSK = new GenerateSSK(identifier);
341                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>(new KeyGenerationResult(identifier));
342                 keyGenerationCallbacks.put(identifier, keyGenerationCallback);
343                 fcpConnection.sendMessage(generateSSK);
344                 return keyGenerationCallback;
345         }
346
347         /**
348          * Sets whether to watch the global queue.
349          *
350          * @param enabled
351          *            <code>true</code> to watch the global queue in addition to the
352          *            client-local queue, <code>false</code> to only watch the
353          *            client-local queue
354          * @throws IOException
355          *             if an I/O error occurs communicating with the node
356          * @throws HighLevelException
357          *             if the client is not connected
358          */
359         public void setWatchGlobal(boolean enabled) throws IOException, HighLevelException {
360                 checkConnection();
361                 WatchGlobal watchGlobal = new WatchGlobal(enabled);
362                 fcpConnection.sendMessage(watchGlobal);
363         }
364
365         /**
366          * Gets a list of all peers from the node.
367          *
368          * @return A callback with the peer list
369          * @throws IOException
370          *             if an I/O error occurs with the node
371          * @throws HighLevelException
372          *             if the client is not connected
373          */
374         public HighLevelCallback<PeerListResult> getPeers() throws IOException, HighLevelException {
375                 checkConnection();
376                 String identifier = generateIdentifier("listPeers");
377                 ListPeers listPeers = new ListPeers(identifier, true, true);
378                 HighLevelCallback<PeerListResult> peerListCallback = new HighLevelCallback<PeerListResult>(new PeerListResult(identifier));
379                 peerListCallbacks.put(identifier, peerListCallback);
380                 fcpConnection.sendMessage(listPeers);
381                 return peerListCallback;
382         }
383
384         /**
385          * Adds the peer whose noderef is stored in the given file.
386          *
387          * @param nodeRefFile
388          *            The name of the file the peer’s noderef is stored in
389          * @return A peer callback
390          * @throws IOException
391          *             if an I/O error occurs communicating with the node
392          * @throws HighLevelException
393          *             if the client is not connected
394          */
395         public HighLevelCallback<PeerResult> addPeer(String nodeRefFile) throws IOException, HighLevelException {
396                 checkConnection();
397                 String identifier = generateIdentifier("addPeer");
398                 AddPeer addPeer = new AddPeer(nodeRefFile);
399                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
400                 peerCallbacks.put(identifier, peerCallback);
401                 fcpConnection.sendMessage(addPeer);
402                 return peerCallback;
403         }
404
405         /**
406          * Adds the peer whose noderef is stored in the given file.
407          *
408          * @param nodeRefURL
409          *            The URL where the peer’s noderef is stored
410          * @return A peer callback
411          * @throws IOException
412          *             if an I/O error occurs communicating with the node
413          * @throws HighLevelException
414          *             if the client is not connected
415          */
416         public HighLevelCallback<PeerResult> addPeer(URL nodeRefURL) throws IOException, HighLevelException {
417                 checkConnection();
418                 String identifier = generateIdentifier("addPeer");
419                 AddPeer addPeer = new AddPeer(nodeRefURL);
420                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
421                 peerCallbacks.put(identifier, peerCallback);
422                 fcpConnection.sendMessage(addPeer);
423                 return peerCallback;
424         }
425
426         /**
427          * Adds the peer whose noderef is stored in the given file.
428          *
429          * @param nodeRef
430          *            The peer’s noderef
431          * @return A peer callback
432          * @throws IOException
433          *             if an I/O error occurs communicating with the node
434          * @throws HighLevelException
435          *             if the client is not connected
436          */
437         public HighLevelCallback<PeerResult> addPeer(NodeRef nodeRef) throws IOException, HighLevelException {
438                 checkConnection();
439                 String identifier = generateIdentifier("addPeer");
440                 AddPeer addPeer = new AddPeer(nodeRef);
441                 HighLevelCallback<PeerResult> peerCallback = new HighLevelCallback<PeerResult>(new PeerResult(identifier));
442                 peerCallbacks.put(identifier, peerCallback);
443                 fcpConnection.sendMessage(addPeer);
444                 return peerCallback;
445         }
446
447         /**
448          * Checks whether direct disk access for the given directory is possible.
449          * You have to perform this check before you can upload or download anything
450          * from or the disk directly!
451          *
452          * @param directory
453          *            The directory to check
454          * @param wantRead
455          *            Whether you want to read the given directory
456          * @param wantWrite
457          *            Whether you want to write to the given directory
458          * @return A direct disk access callback
459          * @throws IOException
460          *             if an I/O error occurs communicating with the node
461          * @throws HighLevelException
462          *             if the client is not connected
463          */
464         public HighLevelCallback<DirectDiskAccessResult> checkDirectDiskAccess(String directory, boolean wantRead, boolean wantWrite) throws IOException, HighLevelException {
465                 checkConnection();
466                 TestDDARequest testDDARequest = new TestDDARequest(directory, wantRead, wantWrite);
467                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = new HighLevelCallback<DirectDiskAccessResult>(new DirectDiskAccessResult(directory));
468                 directDiskAccessCallbacks.put(directory, directDiskAccessCallback);
469                 fcpConnection.sendMessage(testDDARequest);
470                 return directDiskAccessCallback;
471         }
472
473         /**
474          * Starts a download. Files can either be download to disk or streamed from
475          * the node. When downloading to disk you have to perform a direct disk
476          * access check for the directory you want to put the downloaded file in!
477          *
478          * @see #checkDirectDiskAccess(String, boolean, boolean)
479          * @param uri
480          *            The URI to get
481          * @param filename
482          *            The filename to save the data to, or <code>null</code> to
483          *            retrieve the data as InputStream from the
484          *            {@link DownloadResult}
485          * @param global
486          *            Whether to put the download on the global queue
487          * @return A download result
488          * @throws IOException
489          *             if an I/O error occurs communicating with the node
490          * @throws HighLevelException
491          *             if the client is not connected
492          */
493         public HighLevelProgressCallback<DownloadResult> download(String uri, String filename, boolean global) throws IOException, HighLevelException {
494                 checkConnection();
495                 String identifier = generateIdentifier("download");
496                 ClientGet clientGet = new ClientGet(uri, identifier, (filename == null) ? ReturnType.direct : ReturnType.disk);
497                 clientGet.setGlobal(global);
498                 HighLevelProgressCallback<DownloadResult> downloadCallback = new HighLevelProgressCallback<DownloadResult>(new DownloadResult(identifier));
499                 downloadCallbacks.put(identifier, downloadCallback);
500                 fcpConnection.sendMessage(clientGet);
501                 return downloadCallback;
502         }
503
504         /**
505          * Requests a list of all running requests from the node.
506          *
507          * @return The request list result
508          * @throws IOException
509          *             if an I/O errors communicating with the node
510          * @throws HighLevelException
511          *             if the client is not connected
512          */
513         public HighLevelCallback<RequestListResult> getRequests() throws IOException, HighLevelException {
514                 checkConnection();
515                 String identifier = generateIdentifier("list-persistent-requests");
516                 ListPersistentRequests listPersistentRequests = new ListPersistentRequests();
517                 synchronized (syncObject) {
518                         if (requestListCallback != null) {
519                                 logger.log(Level.SEVERE, "getRequests() called with request still running!");
520                         }
521                         requestListCallback = new HighLevelCallback<RequestListResult>(new RequestListResult(identifier));
522                 }
523                 fcpConnection.sendMessage(listPersistentRequests);
524                 return requestListCallback;
525         }
526
527         //
528         // PRIVATE METHODS
529         //
530
531         /**
532          * Checks whether the client is already connected and throws an exception if
533          * it is not.
534          *
535          * @throws NotConnectedException
536          *             if the client is not connected
537          */
538         private void checkConnection() throws NotConnectedException {
539                 synchronized (this) {
540                         if (fcpConnection == null) {
541                                 throw new NotConnectedException("client is not connected");
542                         }
543                 }
544         }
545
546         /**
547          * Generates an identifier for the given function.
548          *
549          * @param function
550          *            The name of the function
551          * @return An identifier
552          */
553         private String generateIdentifier(String function) {
554                 return "jFCPlib-" + function + "-" + System.currentTimeMillis();
555         }
556
557         /**
558          * Disconnects the client from the node, handing the given Throwable to
559          * {@link #fireClientDisconnected(Throwable)}.
560          *
561          * @param throwable
562          *            The exception that caused the disconnect, or <code>null</code>
563          *            if there was no exception
564          */
565         private void disconnect(Throwable throwable) {
566                 if (fcpConnection != null) {
567                         fcpConnection.close();
568                 }
569                 fcpConnection = null;
570         }
571
572         /**
573          * FCP listener for {@link HighLevelClient}.
574          *
575          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
576          */
577         private class HighLevelClientFcpListener implements FcpListener {
578
579                 /** Mapping from directory to written file (for cleanup). */
580                 private final Map<DirectDiskAccessResult, String> writtenFiles = new HashMap<DirectDiskAccessResult, String>();
581
582                 /**
583                  * Creates a new FCP listener for {@link HighLevelClient}.
584                  */
585                 HighLevelClientFcpListener() {
586                         /* do nothing. */
587                 }
588
589                 //
590                 // PRIVATE METHODS
591                 //
592
593                 /**
594                  * Searches all callback collections for a callback with the given
595                  * identifier and cancels it.
596                  *
597                  * @param identifier
598                  *            The identifier to search for, or <code>null</code> to
599                  *            cancel all pending requests
600                  */
601                 @SuppressWarnings("synthetic-access")
602                 private void cancelIdentifier(String identifier) {
603                         synchronized (syncObject) {
604                                 if (connectCallback != null) {
605                                         connectCallback.getIntermediaryResult().setFailed(true);
606                                         connectCallback.setDone();
607                                         connectCallback = null;
608                                 }
609                                 if (requestListCallback != null) {
610                                         requestListCallback.getIntermediaryResult().setFailed(true);
611                                         requestListCallback.setDone();
612                                         requestListCallback = null;
613                                 }
614                         }
615                         if (identifier == null) {
616                                 /* key generation callbacks */
617                                 for (Entry<String, HighLevelCallback<KeyGenerationResult>> keyGenerationEntry : keyGenerationCallbacks.entrySet()) {
618                                         keyGenerationEntry.getValue().getIntermediaryResult().setFailed(true);
619                                         keyGenerationEntry.getValue().setDone();
620                                 }
621                                 keyGenerationCallbacks.clear();
622                                 /* peer list callbacks. */
623                                 for (Entry<String, HighLevelCallback<PeerListResult>> peerListEntry : peerListCallbacks.entrySet()) {
624                                         peerListEntry.getValue().getIntermediaryResult().setFailed(true);
625                                         peerListEntry.getValue().setDone();
626                                 }
627                                 peerListCallbacks.clear();
628                                 /* peer callbacks. */
629                                 for (Entry<String, HighLevelCallback<PeerResult>> peerEntry : peerCallbacks.entrySet()) {
630                                         peerEntry.getValue().getIntermediaryResult().setFailed(true);
631                                         peerEntry.getValue().setDone();
632                                 }
633                                 peerCallbacks.clear();
634                                 /* direct disk access callbacks. */
635                                 for (Entry<String, HighLevelCallback<DirectDiskAccessResult>> directDiskAccessEntry : directDiskAccessCallbacks.entrySet()) {
636                                         directDiskAccessEntry.getValue().getIntermediaryResult().setFailed(true);
637                                         directDiskAccessEntry.getValue().setDone();
638                                 }
639                                 directDiskAccessCallbacks.clear();
640                                 /* download callbacks. */
641                                 for (Entry<String, HighLevelProgressCallback<DownloadResult>> downloadEntry : downloadCallbacks.entrySet()) {
642                                         downloadEntry.getValue().getIntermediaryResult().setFailed(true);
643                                         downloadEntry.getValue().setDone();
644                                 }
645                                 downloadCallbacks.clear();
646                         } else {
647                                 HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
648                                 if (keyGenerationCallback != null) {
649                                         keyGenerationCallback.getIntermediaryResult().setFailed(true);
650                                         keyGenerationCallback.setDone();
651                                         return;
652                                 }
653                                 HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
654                                 if (peerListCallback != null) {
655                                         peerListCallback.getIntermediaryResult().setFailed(true);
656                                         peerListCallback.setDone();
657                                         return;
658                                 }
659                                 HighLevelCallback<PeerResult> peerCallback = peerCallbacks.remove(identifier);
660                                 if (peerCallback != null) {
661                                         peerCallback.getIntermediaryResult().setFailed(true);
662                                         peerCallback.setDone();
663                                         return;
664                                 }
665                                 HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(identifier);
666                                 if (directDiskAccessCallback != null) {
667                                         directDiskAccessCallback.getIntermediaryResult().setFailed(true);
668                                         directDiskAccessCallback.setDone();
669                                         return;
670                                 }
671                                 HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
672                                 if (downloadCallback != null) {
673                                         downloadCallback.getIntermediaryResult().setFailed(true);
674                                         downloadCallback.setDone();
675                                         return;
676                                 }
677                         }
678                 }
679
680                 /**
681                  * Reads the given file and returns the first line of the file.
682                  *
683                  * @param readFilename
684                  *            The name of the file to read
685                  * @return The content of the file
686                  */
687                 private String readContent(String readFilename) {
688                         FileReader fileReader = null;
689                         BufferedReader bufferedFileReader = null;
690                         try {
691                                 fileReader = new FileReader(readFilename);
692                                 bufferedFileReader = new BufferedReader(fileReader);
693                                 String content = bufferedFileReader.readLine();
694                                 return content;
695                         } catch (IOException ioe1) {
696                                 /* swallow. */
697                         } finally {
698                                 FcpUtils.close(bufferedFileReader);
699                                 FcpUtils.close(fileReader);
700                         }
701                         return null;
702                 }
703
704                 /**
705                  * Writes the given content to the given file.
706                  *
707                  * @param directDiskAccessResult
708                  *            The DDA result
709                  * @param writeFilename
710                  *            The name of the file to write to
711                  * @param writeContent
712                  *            The content to write to the file
713                  */
714                 private void writeContent(DirectDiskAccessResult directDiskAccessResult, String writeFilename, String writeContent) {
715                         if ((writeFilename == null) || (writeContent == null)) {
716                                 return;
717                         }
718                         writtenFiles.put(directDiskAccessResult, writeFilename);
719                         FileWriter fileWriter = null;
720                         try {
721                                 fileWriter = new FileWriter(writeFilename);
722                                 fileWriter.write(writeContent);
723                         } catch (IOException ioe1) {
724                                 /* swallow. */
725                         } finally {
726                                 FcpUtils.close(fileWriter);
727                         }
728                 }
729
730                 /**
731                  * Cleans up any files that written for the given result.
732                  *
733                  * @param directDiskAccessResult
734                  *            The direct disk access result
735                  */
736                 @SuppressWarnings("synthetic-access")
737                 private void cleanFiles(DirectDiskAccessResult directDiskAccessResult) {
738                         String writeFilename = writtenFiles.remove(directDiskAccessResult);
739                         if (writeFilename != null) {
740                                 if (!new File(writeFilename).delete()) {
741                                         logger.warning("could not delete " + writeFilename);
742                                 }
743                         }
744                 }
745
746                 //
747                 // INTERFACE FcpListener
748                 //
749
750                 /**
751                  * @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection,
752                  *      Throwable)
753                  */
754                 @SuppressWarnings("synthetic-access")
755                 public void connectionClosed(FcpConnection fcpConnection, Throwable throwable) {
756                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
757                                 return;
758                         }
759                         cancelIdentifier(null);
760                         disconnect(throwable);
761                         fireClientDisconnected(throwable);
762                 }
763
764                 /**
765                  * @see net.pterodactylus.fcp.FcpListener#receivedAllData(net.pterodactylus.fcp.FcpConnection,
766                  *      net.pterodactylus.fcp.AllData)
767                  */
768                 public void receivedAllData(FcpConnection fcpConnection, AllData allData) {
769                         /* TODO */
770                 }
771
772                 /**
773                  * @see net.pterodactylus.fcp.FcpListener#receivedCloseConnectionDuplicateClientName(net.pterodactylus.fcp.FcpConnection,
774                  *      net.pterodactylus.fcp.CloseConnectionDuplicateClientName)
775                  */
776                 public void receivedCloseConnectionDuplicateClientName(FcpConnection fcpConnection, CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
777                         /* TODO */
778                 }
779
780                 /**
781                  * @see net.pterodactylus.fcp.FcpListener#receivedConfigData(net.pterodactylus.fcp.FcpConnection,
782                  *      net.pterodactylus.fcp.ConfigData)
783                  */
784                 public void receivedConfigData(FcpConnection fcpConnection, ConfigData configData) {
785                         /* TODO */
786                 }
787
788                 /**
789                  * @see net.pterodactylus.fcp.FcpListener#receivedDataFound(net.pterodactylus.fcp.FcpConnection,
790                  *      net.pterodactylus.fcp.DataFound)
791                  */
792                 @SuppressWarnings("synthetic-access")
793                 public void receivedDataFound(FcpConnection fcpConnection, DataFound dataFound) {
794                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
795                                 return;
796                         }
797                         String identifier = dataFound.getIdentifier();
798                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
799                         if (downloadCallback != null) {
800                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
801                                 downloadResult.setFinished(true);
802                                 downloadResult.setFailed(false);
803                                 downloadCallback.progressUpdated();
804                                 downloadCallback.setDone();
805                         }
806                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier, true);
807                         fireProgressReceived(identifier, highLevelProgress);
808                 }
809
810                 /**
811                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeerNotes(net.pterodactylus.fcp.FcpConnection,
812                  *      net.pterodactylus.fcp.EndListPeerNotes)
813                  */
814                 public void receivedEndListPeerNotes(FcpConnection fcpConnection, EndListPeerNotes endListPeerNotes) {
815                         /* TODO */
816                 }
817
818                 /**
819                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
820                  *      net.pterodactylus.fcp.EndListPeers)
821                  */
822                 @SuppressWarnings("synthetic-access")
823                 public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
824                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
825                                 return;
826                         }
827                         String identifier = endListPeers.getIdentifier();
828                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
829                         if (peerListCallback == null) {
830                                 return;
831                         }
832                         peerListCallback.setDone();
833                 }
834
835                 /**
836                  * @see net.pterodactylus.fcp.FcpListener#receivedEndListPersistentRequests(net.pterodactylus.fcp.FcpConnection,
837                  *      net.pterodactylus.fcp.EndListPersistentRequests)
838                  */
839                 @SuppressWarnings("synthetic-access")
840                 public void receivedEndListPersistentRequests(FcpConnection fcpConnection, EndListPersistentRequests endListPersistentRequests) {
841                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
842                                 return;
843                         }
844                         synchronized (syncObject) {
845                                 if (HighLevelClient.this.requestListCallback == null) {
846                                         logger.log(Level.WARNING, "got EndListPersistentRequests without running request!");
847                                         return;
848                                 }
849                                 requestListCallback.setDone();
850                                 requestListCallback = null;
851                         }
852                 }
853
854                 /**
855                  * @see net.pterodactylus.fcp.FcpListener#receivedFCPPluginReply(net.pterodactylus.fcp.FcpConnection,
856                  *      net.pterodactylus.fcp.FCPPluginReply)
857                  */
858                 public void receivedFCPPluginReply(FcpConnection fcpConnection, FCPPluginReply fcpPluginReply) {
859                         /* TODO */
860                 }
861
862                 /**
863                  * @see net.pterodactylus.fcp.FcpListener#receivedGetFailed(net.pterodactylus.fcp.FcpConnection,
864                  *      net.pterodactylus.fcp.GetFailed)
865                  */
866                 @SuppressWarnings("synthetic-access")
867                 public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) {
868                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
869                                 return;
870                         }
871                         String identifier = getFailed.getIdentifier();
872                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.remove(identifier);
873                         if (downloadCallback != null) {
874                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
875                                 downloadResult.setFailed(true);
876                                 downloadResult.setFinished(true);
877                                 downloadCallback.setDone();
878                                 return;
879                         }
880                         /* unknown identifier? */
881                         logger.warning("unknown identifier for GetFailed: " + identifier);
882                 }
883
884                 /**
885                  * @see net.pterodactylus.fcp.FcpListener#receivedIdentifierCollision(net.pterodactylus.fcp.FcpConnection,
886                  *      net.pterodactylus.fcp.IdentifierCollision)
887                  */
888                 public void receivedIdentifierCollision(FcpConnection fcpConnection, IdentifierCollision identifierCollision) {
889                         /* TODO */
890                 }
891
892                 /**
893                  * @see net.pterodactylus.fcp.FcpListener#receivedMessage(net.pterodactylus.fcp.FcpConnection,
894                  *      net.pterodactylus.fcp.FcpMessage)
895                  */
896                 public void receivedMessage(FcpConnection fcpConnection, FcpMessage fcpMessage) {
897                         /* TODO */
898                 }
899
900                 /**
901                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeData(net.pterodactylus.fcp.FcpConnection,
902                  *      net.pterodactylus.fcp.NodeData)
903                  */
904                 public void receivedNodeData(FcpConnection fcpConnection, NodeData nodeData) {
905                         /* TODO */
906                 }
907
908                 /**
909                  * @see net.pterodactylus.fcp.FcpListener#receivedNodeHello(net.pterodactylus.fcp.FcpConnection,
910                  *      net.pterodactylus.fcp.NodeHello)
911                  */
912                 @SuppressWarnings("synthetic-access")
913                 public void receivedNodeHello(FcpConnection fcpConnection, NodeHello nodeHello) {
914                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
915                                 return;
916                         }
917                         synchronized (syncObject) {
918                                 connectCallback.getIntermediaryResult().setFailed(false);
919                                 connectCallback.setDone();
920                                 connectCallback = null;
921                         }
922                         fireClientConnected();
923                 }
924
925                 /**
926                  * @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
927                  *      net.pterodactylus.fcp.Peer)
928                  */
929                 @SuppressWarnings("synthetic-access")
930                 public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
931                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
932                                 return;
933                         }
934                         String identifier = peer.getIdentifier();
935                         if (identifier == null) {
936                                 return;
937                         }
938                         HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
939                         if (peerListCallback != null) {
940                                 peerListCallback.getIntermediaryResult().addPeer(peer);
941                                 return;
942                         }
943                         HighLevelCallback<PeerResult> peerResult = peerCallbacks.remove(identifier);
944                         if (peerResult != null) {
945                                 peerResult.getIntermediaryResult().setPeer(peer);
946                                 peerResult.setDone();
947                                 return;
948                         }
949                         logger.warning("got Peer message with unknown identifier: " + identifier);
950                 }
951
952                 /**
953                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerNote(net.pterodactylus.fcp.FcpConnection,
954                  *      net.pterodactylus.fcp.PeerNote)
955                  */
956                 public void receivedPeerNote(FcpConnection fcpConnection, PeerNote peerNote) {
957                         /* TODO */
958                 }
959
960                 /**
961                  * @see net.pterodactylus.fcp.FcpListener#receivedPeerRemoved(net.pterodactylus.fcp.FcpConnection,
962                  *      net.pterodactylus.fcp.PeerRemoved)
963                  */
964                 public void receivedPeerRemoved(FcpConnection fcpConnection, PeerRemoved peerRemoved) {
965                         /* TODO */
966                 }
967
968                 /**
969                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentGet(net.pterodactylus.fcp.FcpConnection,
970                  *      net.pterodactylus.fcp.PersistentGet)
971                  */
972                 @SuppressWarnings("synthetic-access")
973                 public void receivedPersistentGet(FcpConnection fcpConnection, PersistentGet persistentGet) {
974                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
975                                 return;
976                         }
977                         synchronized (syncObject) {
978                                 if (requestListCallback != null) {
979                                         RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
980                                         requestListResult.addRequestResult(new GetRequestResult(persistentGet));
981                                         return;
982                                 }
983                         }
984                         String identifier = persistentGet.getIdentifier();
985                         if (downloadCallbacks.containsKey(identifier)) {
986                                 /* TODO */
987                                 return;
988                         }
989                 }
990
991                 /**
992                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.fcp.FcpConnection,
993                  *      net.pterodactylus.fcp.PersistentPut)
994                  */
995                 @SuppressWarnings("synthetic-access")
996                 public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
997                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
998                                 return;
999                         }
1000                         synchronized (syncObject) {
1001                                 if (requestListCallback != null) {
1002                                         RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
1003                                         requestListResult.addRequestResult(new PutRequestResult(persistentPut));
1004                                         return;
1005                                 }
1006                         }
1007                 }
1008
1009                 /**
1010                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentPutDir(net.pterodactylus.fcp.FcpConnection,
1011                  *      net.pterodactylus.fcp.PersistentPutDir)
1012                  */
1013                 @SuppressWarnings("synthetic-access")
1014                 public void receivedPersistentPutDir(FcpConnection fcpConnection, PersistentPutDir persistentPutDir) {
1015                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1016                                 return;
1017                         }
1018                         synchronized (syncObject) {
1019                                 if (requestListCallback != null) {
1020                                         RequestListResult requestListResult = requestListCallback.getIntermediaryResult();
1021                                         requestListResult.addRequestResult(new PutDirRequestResult(persistentPutDir));
1022                                         return;
1023                                 }
1024                         }
1025                 }
1026
1027                 /**
1028                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestModified(net.pterodactylus.fcp.FcpConnection,
1029                  *      net.pterodactylus.fcp.PersistentRequestModified)
1030                  */
1031                 public void receivedPersistentRequestModified(FcpConnection fcpConnection, PersistentRequestModified persistentRequestModified) {
1032                         /* TODO */
1033                 }
1034
1035                 /**
1036                  * @see net.pterodactylus.fcp.FcpListener#receivedPersistentRequestRemoved(net.pterodactylus.fcp.FcpConnection,
1037                  *      net.pterodactylus.fcp.PersistentRequestRemoved)
1038                  */
1039                 public void receivedPersistentRequestRemoved(FcpConnection fcpConnection, PersistentRequestRemoved persistentRequestRemoved) {
1040                         /* TODO */
1041                 }
1042
1043                 /**
1044                  * @see net.pterodactylus.fcp.FcpListener#receivedPluginInfo(net.pterodactylus.fcp.FcpConnection,
1045                  *      net.pterodactylus.fcp.PluginInfo)
1046                  */
1047                 public void receivedPluginInfo(FcpConnection fcpConnection, PluginInfo pluginInfo) {
1048                         /* TODO */
1049                 }
1050
1051                 /**
1052                  * @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
1053                  *      net.pterodactylus.fcp.ProtocolError)
1054                  */
1055                 @SuppressWarnings("synthetic-access")
1056                 public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
1057                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1058                                 return;
1059                         }
1060                         String identifier = protocolError.getIdentifier();
1061                         if (identifier == null) {
1062                                 return;
1063                         }
1064                         cancelIdentifier(identifier);
1065                 }
1066
1067                 /**
1068                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFailed(net.pterodactylus.fcp.FcpConnection,
1069                  *      net.pterodactylus.fcp.PutFailed)
1070                  */
1071                 @SuppressWarnings("synthetic-access")
1072                 public void receivedPutFailed(FcpConnection fcpConnection, PutFailed putFailed) {
1073                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1074                                 return;
1075                         }
1076                         String identifier = putFailed.getIdentifier();
1077                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
1078                         if (downloadCallback != null) {
1079                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
1080                                 downloadResult.setFailed(true);
1081                                 downloadResult.setFinished(true);
1082                                 downloadCallback.progressUpdated();
1083                                 downloadCallback.setDone();
1084                         }
1085                         /* TODO - check inserts */
1086                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier, true);
1087                         fireProgressReceived(identifier, highLevelProgress);
1088                 }
1089
1090                 /**
1091                  * @see net.pterodactylus.fcp.FcpListener#receivedPutFetchable(net.pterodactylus.fcp.FcpConnection,
1092                  *      net.pterodactylus.fcp.PutFetchable)
1093                  */
1094                 @SuppressWarnings("synthetic-access")
1095                 public void receivedPutFetchable(FcpConnection fcpConnection, PutFetchable putFetchable) {
1096                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1097                                 return;
1098                         }
1099                         String identifier = putFetchable.getIdentifier();
1100                         /* TODO - check inserts */
1101                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier);
1102                         highLevelProgress.setFetchable(true);
1103                         fireProgressReceived(identifier, highLevelProgress);
1104                 }
1105
1106                 /**
1107                  * @see net.pterodactylus.fcp.FcpListener#receivedPutSuccessful(net.pterodactylus.fcp.FcpConnection,
1108                  *      net.pterodactylus.fcp.PutSuccessful)
1109                  */
1110                 @SuppressWarnings("synthetic-access")
1111                 public void receivedPutSuccessful(FcpConnection fcpConnection, PutSuccessful putSuccessful) {
1112                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1113                                 return;
1114                         }
1115                         String identifier = putSuccessful.getIdentifier();
1116                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
1117                         if (downloadCallback != null) {
1118                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
1119                                 downloadResult.setFinished(true);
1120                                 downloadResult.setFailed(false);
1121                                 downloadCallback.progressUpdated();
1122                         }
1123                         /* TODO - check inserts */
1124                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier, true);
1125                         fireProgressReceived(identifier, highLevelProgress);
1126                 }
1127
1128                 /**
1129                  * @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
1130                  *      net.pterodactylus.fcp.SSKKeypair)
1131                  */
1132                 @SuppressWarnings("synthetic-access")
1133                 public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
1134                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1135                                 return;
1136                         }
1137                         HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
1138                         if (keyGenerationCallback == null) {
1139                                 return;
1140                         }
1141                         KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
1142                         keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
1143                         keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
1144                         keyGenerationCallback.setDone();
1145                 }
1146
1147                 /**
1148                  * @see net.pterodactylus.fcp.FcpListener#receivedSimpleProgress(net.pterodactylus.fcp.FcpConnection,
1149                  *      net.pterodactylus.fcp.SimpleProgress)
1150                  */
1151                 @SuppressWarnings("synthetic-access")
1152                 public void receivedSimpleProgress(FcpConnection fcpConnection, SimpleProgress simpleProgress) {
1153                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1154                                 return;
1155                         }
1156                         String identifier = simpleProgress.getIdentifier();
1157                         HighLevelProgressCallback<DownloadResult> downloadCallback = downloadCallbacks.get(identifier);
1158                         if (downloadCallback != null) {
1159                                 DownloadResult downloadResult = downloadCallback.getIntermediaryResult();
1160                                 downloadResult.setTotalBlocks(simpleProgress.getTotal());
1161                                 downloadResult.setRequiredBlocks(simpleProgress.getRequired());
1162                                 downloadResult.setSuccessfulBlocks(simpleProgress.getSucceeded());
1163                                 downloadResult.setFailedBlocks(simpleProgress.getFailed());
1164                                 downloadResult.setFatallyFailedBlocks(simpleProgress.getFatallyFailed());
1165                                 downloadResult.setTotalFinalized(simpleProgress.isFinalizedTotal());
1166                                 downloadCallback.progressUpdated();
1167                         }
1168                         /* TODO - check inserts */
1169                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier, simpleProgress.getTotal(), simpleProgress.getRequired(), simpleProgress.getSucceeded(), simpleProgress.getFailed(), simpleProgress.getFatallyFailed(), simpleProgress.isFinalizedTotal());
1170                         fireProgressReceived(identifier, highLevelProgress);
1171                 }
1172
1173                 /**
1174                  * @see net.pterodactylus.fcp.FcpListener#receivedStartedCompression(net.pterodactylus.fcp.FcpConnection,
1175                  *      net.pterodactylus.fcp.StartedCompression)
1176                  */
1177                 public void receivedStartedCompression(FcpConnection fcpConnection, StartedCompression startedCompression) {
1178                         /* TODO */
1179                 }
1180
1181                 /**
1182                  * @see net.pterodactylus.fcp.FcpListener#receivedSubscribedUSKUpdate(net.pterodactylus.fcp.FcpConnection,
1183                  *      net.pterodactylus.fcp.SubscribedUSKUpdate)
1184                  */
1185                 public void receivedSubscribedUSKUpdate(FcpConnection fcpConnection, SubscribedUSKUpdate subscribedUSKUpdate) {
1186                         /* TODO */
1187                 }
1188
1189                 /**
1190                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAComplete(net.pterodactylus.fcp.FcpConnection,
1191                  *      net.pterodactylus.fcp.TestDDAComplete)
1192                  */
1193                 @SuppressWarnings("synthetic-access")
1194                 public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete) {
1195                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1196                                 return;
1197                         }
1198                         String directory = testDDAComplete.getDirectory();
1199                         if (directory == null) {
1200                                 return;
1201                         }
1202                         HighLevelCallback<DirectDiskAccessResult> directDiskAccessCallback = directDiskAccessCallbacks.remove(directory);
1203                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallback.getIntermediaryResult();
1204                         cleanFiles(directDiskAccessResult);
1205                         directDiskAccessResult.setReadAllowed(testDDAComplete.isReadDirectoryAllowed());
1206                         directDiskAccessResult.setWriteAllowed(testDDAComplete.isWriteDirectoryAllowed());
1207                         directDiskAccessCallback.setDone();
1208                 }
1209
1210                 /**
1211                  * @see net.pterodactylus.fcp.FcpListener#receivedTestDDAReply(net.pterodactylus.fcp.FcpConnection,
1212                  *      net.pterodactylus.fcp.TestDDAReply)
1213                  */
1214                 @SuppressWarnings("synthetic-access")
1215                 public void receivedTestDDAReply(FcpConnection fcpConnection, TestDDAReply testDDAReply) {
1216                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1217                                 return;
1218                         }
1219                         String directory = testDDAReply.getDirectory();
1220                         if (directory == null) {
1221                                 return;
1222                         }
1223                         DirectDiskAccessResult directDiskAccessResult = directDiskAccessCallbacks.get(directory).getIntermediaryResult();
1224                         String readFilename = testDDAReply.getReadFilename();
1225                         String readContent = readContent(readFilename);
1226                         String writeFilename = testDDAReply.getWriteFilename();
1227                         String writeContent = testDDAReply.getContentToWrite();
1228                         writeContent(directDiskAccessResult, writeFilename, writeContent);
1229                         TestDDAResponse testDDAResponse = new TestDDAResponse(directory, readContent);
1230                         try {
1231                                 fcpConnection.sendMessage(testDDAResponse);
1232                         } catch (IOException e) {
1233                                 /* swallow. I’m verry unhappy about this. */
1234                         }
1235                 }
1236
1237                 /**
1238                  * @see net.pterodactylus.fcp.FcpListener#receivedURIGenerated(net.pterodactylus.fcp.FcpConnection,
1239                  *      net.pterodactylus.fcp.URIGenerated)
1240                  */
1241                 @SuppressWarnings("synthetic-access")
1242                 public void receivedURIGenerated(FcpConnection fcpConnection, URIGenerated uriGenerated) {
1243                         if (fcpConnection != HighLevelClient.this.fcpConnection) {
1244                                 return;
1245                         }
1246                         String identifier = uriGenerated.getIdentifier();
1247                         /* TODO - check inserts */
1248                         HighLevelProgress highLevelProgress = new HighLevelProgress(identifier, uriGenerated.getURI());
1249                         fireProgressReceived(identifier, highLevelProgress);
1250                 }
1251
1252                 /**
1253                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownNodeIdentifier(net.pterodactylus.fcp.FcpConnection,
1254                  *      net.pterodactylus.fcp.UnknownNodeIdentifier)
1255                  */
1256                 public void receivedUnknownNodeIdentifier(FcpConnection fcpConnection, UnknownNodeIdentifier unknownNodeIdentifier) {
1257                         /* TODO */
1258                 }
1259
1260                 /**
1261                  * @see net.pterodactylus.fcp.FcpListener#receivedUnknownPeerNoteType(net.pterodactylus.fcp.FcpConnection,
1262                  *      net.pterodactylus.fcp.UnknownPeerNoteType)
1263                  */
1264                 public void receivedUnknownPeerNoteType(FcpConnection fcpConnection, UnknownPeerNoteType unknownPeerNoteType) {
1265                         /* TODO */
1266                 }
1267
1268                 /**
1269                  * @see net.pterodactylus.fcp.FcpListener#receviedFinishedCompression(net.pterodactylus.fcp.FcpConnection,
1270                  *      net.pterodactylus.fcp.FinishedCompression)
1271                  */
1272                 public void receviedFinishedCompression(FcpConnection fcpConnection, FinishedCompression finishedCompression) {
1273                         /* TODO */
1274                 }
1275
1276         }
1277
1278 }