Generate identifiers randomly
[jFCPlib.git] / src / main / java / net / pterodactylus / fcp / quelaton / ClientGetCommandImpl.java
1 package net.pterodactylus.fcp.quelaton;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.util.Optional;
6 import java.util.concurrent.ExecutorService;
7 import java.util.concurrent.Future;
8 import java.util.concurrent.atomic.AtomicBoolean;
9 import java.util.concurrent.atomic.AtomicReference;
10
11 import net.pterodactylus.fcp.AllData;
12 import net.pterodactylus.fcp.ClientGet;
13 import net.pterodactylus.fcp.FcpMessage;
14 import net.pterodactylus.fcp.FcpUtils.TempInputStream;
15 import net.pterodactylus.fcp.GetFailed;
16 import net.pterodactylus.fcp.Priority;
17 import net.pterodactylus.fcp.ReturnType;
18
19 /**
20  * Implementation of the {@link ClientGetCommand}.
21  *
22  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
23  */
24 class ClientGetCommandImpl implements ClientGetCommand {
25
26         private final ExecutorService threadPool;
27         private final ConnectionSupplier connectionSupplier;
28
29         private boolean ignoreDataStore;
30         private boolean dataStoreOnly;
31         private Long maxSize;
32         private Priority priority;
33         private boolean realTime;
34         private boolean global;
35
36         public ClientGetCommandImpl(ExecutorService threadPool, ConnectionSupplier connectionSupplier) {
37                 this.threadPool = threadPool;
38                 this.connectionSupplier = connectionSupplier;
39         }
40
41         @Override
42         public ClientGetCommand ignoreDataStore() {
43                 ignoreDataStore = true;
44                 return this;
45         }
46
47         @Override
48         public ClientGetCommand dataStoreOnly() {
49                 dataStoreOnly = true;
50                 return this;
51         }
52
53         @Override
54         public ClientGetCommand maxSize(long maxSize) {
55                 this.maxSize = maxSize;
56                 return this;
57         }
58
59         @Override
60         public ClientGetCommand priority(Priority priority) {
61                 this.priority = priority;
62                 return this;
63         }
64
65         @Override
66         public ClientGetCommand realTime() {
67                 realTime = true;
68                 return this;
69         }
70
71         @Override
72         public ClientGetCommand global() {
73                 global = true;
74                 return this;
75         }
76
77         @Override
78         public Future<Optional<Data>> uri(String uri) {
79                 ClientGet clientGet = createClientGetCommand(uri);
80                 return threadPool.submit(() -> new ClientGetReplySequence().send(clientGet).get());
81         }
82
83         private ClientGet createClientGetCommand(String uri) {
84                 String identifier = new RandomIdentifierGenerator().generate();
85                 ClientGet clientGet = new ClientGet(uri, identifier, ReturnType.direct);
86                 if (ignoreDataStore) {
87                         clientGet.setIgnoreDataStore(true);
88                 }
89                 if (dataStoreOnly) {
90                         clientGet.setDataStoreOnly(true);
91                 }
92                 if (maxSize != null) {
93                         clientGet.setMaxSize(maxSize);
94                 }
95                 if (priority != null) {
96                         clientGet.setPriority(priority);
97                 }
98                 if (realTime) {
99                         clientGet.setRealTimeFlag(true);
100                 }
101                 if (global) {
102                         clientGet.setGlobal(true);
103                 }
104                 return clientGet;
105         }
106
107         private class ClientGetReplySequence extends FcpReplySequence<Optional<Data>> {
108
109                 private final AtomicReference<String> identifier = new AtomicReference<>();
110                 private final AtomicBoolean finished = new AtomicBoolean();
111                 private final AtomicBoolean failed = new AtomicBoolean();
112
113                 private String contentType;
114                 private long dataLength;
115                 private InputStream payload;
116
117                 public ClientGetReplySequence() throws IOException {
118                         super(ClientGetCommandImpl.this.threadPool, ClientGetCommandImpl.this.connectionSupplier.get());
119                 }
120
121                 @Override
122                 protected boolean isFinished() {
123                         return finished.get() || failed.get();
124                 }
125
126                 @Override
127                 protected Optional<Data> getResult() {
128                         return failed.get() ? Optional.empty() : Optional.of(new Data() {
129                                 @Override
130                                 public String getMimeType() {
131                                         return contentType;
132                                 }
133
134                                 @Override
135                                 public long size() {
136                                         return dataLength;
137                                 }
138
139                                 @Override
140                                 public InputStream getInputStream() {
141                                         return payload;
142                                 }
143                         });
144                 }
145
146                 @Override
147                 protected void consumeAllData(AllData allData) {
148                         if (allData.getIdentifier().equals(identifier.get())) {
149                                 synchronized (this) {
150                                         contentType = allData.getContentType();
151                                         dataLength = allData.getDataLength();
152                                         try {
153                                                 payload = new TempInputStream(allData.getPayloadInputStream(), dataLength);
154                                                 finished.set(true);
155                                         } catch (IOException e) {
156                                                 // TODO – logging
157                                                 failed.set(true);
158                                         }
159                                 }
160                         }
161                 }
162
163                 @Override
164                 protected void consumeGetFailed(GetFailed getFailed) {
165                         if (getFailed.getIdentifier().equals(identifier.get())) {
166                                 failed.set(true);
167                         }
168                 }
169
170                 @Override
171                 protected void consumeConnectionClosed(Throwable throwable) {
172                         failed.set(true);
173                 }
174
175                 @Override
176                 public Future<Optional<Data>> send(FcpMessage fcpMessage) throws IOException {
177                         identifier.set(fcpMessage.getField("Identifier"));
178                         return super.send(fcpMessage);
179                 }
180
181         }
182
183 }