Refactor anonymous to inner class
[jFCPlib.git] / src / main / java / net / pterodactylus / fcp / quelaton / DefaultFcpClient.java
1 package net.pterodactylus.fcp.quelaton;
2
3 import java.io.IOException;
4 import java.util.concurrent.ExecutionException;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.atomic.AtomicBoolean;
7 import java.util.concurrent.atomic.AtomicReference;
8 import java.util.function.Supplier;
9
10 import net.pterodactylus.fcp.ClientHello;
11 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
12 import net.pterodactylus.fcp.FcpConnection;
13 import net.pterodactylus.fcp.NodeHello;
14
15 /**
16  * Default {@link FcpClient} implementation.
17  *
18  * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
19  */
20 public class DefaultFcpClient implements FcpClient {
21
22         private final ExecutorService threadPool;
23         private final String hostname;
24         private final int port;
25         private final AtomicReference<FcpConnection> fcpConnection = new AtomicReference<>();
26         private final Supplier<String> clientName;
27         private final Supplier<String> expectedVersion;
28
29         public DefaultFcpClient(ExecutorService threadPool, String hostname, int port, Supplier<String> clientName,
30                 Supplier<String> expectedVersion) {
31                 this.threadPool = threadPool;
32                 this.hostname = hostname;
33                 this.port = port;
34                 this.clientName = clientName;
35                 this.expectedVersion = expectedVersion;
36         }
37
38         private FcpConnection connect() throws IOException {
39                 FcpConnection fcpConnection = this.fcpConnection.get();
40                 if (fcpConnection != null) {
41                         return fcpConnection;
42                 }
43                 fcpConnection = createConnection();
44                 this.fcpConnection.compareAndSet(null, fcpConnection);
45                 return fcpConnection;
46         }
47
48         private FcpConnection createConnection() throws IOException {
49                 FcpConnection connection = new FcpConnection(hostname, port);
50                 connection.connect();
51                 FcpReplySequence<?> nodeHelloSequence = new ClientHelloReplySequence(connection);
52                 ClientHello clientHello = new ClientHello(clientName.get(), expectedVersion.get());
53                 try {
54                         nodeHelloSequence.send(clientHello).get();
55                 } catch (InterruptedException | ExecutionException e) {
56                         connection.close();
57                         throw new IOException(String.format("Could not connect to %s:%d.", hostname, port), e);
58                 }
59                 return connection;
60         }
61
62         @Override
63         public GenerateKeypairCommand generateKeypair() {
64                 return new GenerateKeypairCommandImpl(threadPool, this::connect);
65         }
66
67         @Override
68         public ClientGetCommand clientGet() {
69                 return new ClientGetCommandImpl(threadPool, this::connect);
70         }
71
72         private class ClientHelloReplySequence extends FcpReplySequence<Void> {
73
74                 private final AtomicReference<NodeHello> receivedNodeHello;
75                 private final AtomicBoolean receivedClosed;
76
77                 public ClientHelloReplySequence(FcpConnection connection) {
78                         super(DefaultFcpClient.this.threadPool, connection);
79                         receivedNodeHello = new AtomicReference<>();
80                         receivedClosed = new AtomicBoolean();
81                 }
82
83                 @Override
84                 protected boolean isFinished() {
85                         return receivedNodeHello.get() != null || receivedClosed.get();
86                 }
87
88                 @Override
89                 protected void consumeNodeHello(NodeHello nodeHello) {
90                         receivedNodeHello.set(nodeHello);
91                 }
92
93                 @Override
94                 protected void consumeCloseConnectionDuplicateClientName(
95                         CloseConnectionDuplicateClientName closeConnectionDuplicateClientName) {
96                         receivedClosed.set(true);
97                 }
98
99         }
100
101 }
102