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