3ded685a0c4877af938292fcb23ad28e4601c5f4
[jFCPlib.git] / src / main / java / net / pterodactylus / fcp / quelaton / ClientHelloImpl.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.AtomicReference;
7
8 import net.pterodactylus.fcp.ClientHello;
9 import net.pterodactylus.fcp.FcpConnection;
10 import net.pterodactylus.fcp.NodeHello;
11
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15
16 /**
17  * Internal <code>ClientHello</code> implementation based on {@link FcpDialog}.
18  *
19  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
20  */
21 public class ClientHelloImpl {
22
23         private final ListeningExecutorService threadPool;
24         private final String hostname;
25         private final int port;
26         private final AtomicReference<String> clientName = new AtomicReference<>();
27
28         public ClientHelloImpl(ExecutorService threadPool, String hostname, int port) {
29                 this.threadPool = MoreExecutors.listeningDecorator(threadPool);
30                 this.hostname = hostname;
31                 this.port = port;
32         }
33
34         public Executable<FcpConnection> withName(String name) {
35                 clientName.set(name);
36                 return this::execute;
37         }
38
39         private ListenableFuture<FcpConnection> execute() {
40                 return threadPool.submit(this::establishConnection);
41         }
42
43         private FcpConnection establishConnection() throws IOException {
44                 FcpConnection connection = new FcpConnection(hostname, port);
45                 connection.connect();
46                 ClientHello clientHello = new ClientHello(clientName.get(), "2.0");
47                 try (ClientHelloDialog nodeHelloSequence = new ClientHelloDialog(connection)) {
48                         if (nodeHelloSequence.send(clientHello).get()) {
49                                 return connection;
50                         }
51                 } catch (InterruptedException | ExecutionException e) {
52                         connection.close();
53                         throw new IOException(String.format("Could not connect to %s:%d.", hostname, port), e);
54                 }
55                 connection.close();
56                 throw new IOException(String.format("Could not connect to %s:%d.", hostname, port));
57         }
58
59         private class ClientHelloDialog extends FcpDialog<Boolean> {
60
61                 private final AtomicReference<NodeHello> receivedNodeHello = new AtomicReference<>();
62
63                 public ClientHelloDialog(FcpConnection connection) {
64                         super(ClientHelloImpl.this.threadPool, connection);
65                 }
66
67                 @Override
68                 protected boolean isFinished() {
69                         return receivedNodeHello.get() != null;
70                 }
71
72                 @Override
73                 protected Boolean getResult() {
74                         return receivedNodeHello.get() != null;
75                 }
76
77                 @Override
78                 protected void consumeNodeHello(NodeHello nodeHello) {
79                         receivedNodeHello.set(nodeHello);
80                 }
81
82         }
83
84 }