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