1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.blobstore.internal;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
23
24 import java.util.Set;
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.ExecutorService;
27
28 import javax.inject.Inject;
29 import javax.inject.Named;
30
31 import org.jclouds.Constants;
32 import org.jclouds.blobstore.AsyncBlobStore;
33 import org.jclouds.blobstore.BlobStoreContext;
34 import org.jclouds.blobstore.ContainerNotFoundException;
35 import org.jclouds.blobstore.domain.Blob;
36 import org.jclouds.blobstore.domain.BlobBuilder;
37 import org.jclouds.blobstore.domain.PageSet;
38 import org.jclouds.blobstore.domain.StorageMetadata;
39 import org.jclouds.blobstore.options.ListContainerOptions;
40 import org.jclouds.blobstore.util.BlobUtils;
41 import org.jclouds.blobstore.util.internal.BlobUtilsImpl;
42 import org.jclouds.collect.Memoized;
43 import org.jclouds.domain.Location;
44 import org.jclouds.util.Assertions;
45
46 import com.google.common.base.Supplier;
47 import com.google.common.util.concurrent.Futures;
48 import com.google.common.util.concurrent.ListenableFuture;
49
50
51
52
53
54 public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
55
56 protected final BlobStoreContext context;
57 protected final BlobUtils blobUtils;
58 protected final ExecutorService service;
59 protected final Supplier<Location> defaultLocation;
60 protected final Supplier<Set<? extends Location>> locations;
61
62 @Inject
63 protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
64 @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
65 @Memoized Supplier<Set<? extends Location>> locations) {
66 this.context = checkNotNull(context, "context");
67 this.blobUtils = checkNotNull(blobUtils, "blobUtils");
68 this.service = checkNotNull(service, "service");
69 this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
70 this.locations = checkNotNull(locations, "locations");
71 }
72
73 @Override
74 public BlobStoreContext getContext() {
75 return context;
76 }
77
78
79
80
81 @Override
82 public Blob newBlob(String name) {
83 return blobUtils.newBlob(name);
84 }
85
86
87
88
89 @Override
90 public BlobBuilder blobBuilder(String name) {
91 return blobUtils.blobBuilder().name(name);
92 }
93
94
95
96
97
98
99
100
101 @Override
102 public ListenableFuture<PageSet<? extends StorageMetadata>> list(String container) {
103 return this.list(container, org.jclouds.blobstore.options.ListContainerOptions.NONE);
104 }
105
106
107
108
109
110
111
112
113 @Override
114 public ListenableFuture<Long> countBlobs(String container) {
115 return countBlobs(container, recursive());
116 }
117
118
119
120
121
122
123
124 @Override
125 public ListenableFuture<Long> countBlobs(final String containerName, final ListContainerOptions options) {
126 return org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Long>() {
127 public Long call() throws Exception {
128 return blobUtils.countBlobs(containerName, options);
129 }
130
131 @Override
132 public String toString() {
133 return "countBlobs(" + containerName + ")";
134 }
135 }), service);
136 }
137
138
139
140
141
142
143
144
145 @Override
146 public ListenableFuture<Void> clearContainer(final String container) {
147 return clearContainer(container, recursive());
148 }
149
150
151
152
153
154
155
156 @Override
157 public ListenableFuture<Void> clearContainer(final String containerName, final ListContainerOptions options) {
158 return org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() {
159
160 public Void call() throws Exception {
161 blobUtils.clearContainer(containerName, options);
162 return null;
163 }
164
165 @Override
166 public String toString() {
167 return "clearContainer(" + containerName + ")";
168 }
169 }), service);
170 }
171
172
173
174
175
176
177
178 @Override
179 public ListenableFuture<Void> deleteDirectory(final String containerName, final String directory) {
180 return org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() {
181
182 public Void call() throws Exception {
183 blobUtils.deleteDirectory(containerName, directory);
184 return null;
185 }
186
187 @Override
188 public String toString() {
189 return "deleteDirectory(" + containerName + "," + directory + ")";
190 }
191 }), service);
192 }
193
194
195
196
197
198
199
200
201
202 public ListenableFuture<Boolean> directoryExists(final String containerName, final String directory) {
203 return org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Boolean>() {
204
205 public Boolean call() throws Exception {
206 return blobUtils.directoryExists(containerName, directory);
207 }
208
209 @Override
210 public String toString() {
211 return "directoryExists(" + containerName + "," + directory + ")";
212 }
213 }), service);
214 }
215
216
217
218
219
220
221
222
223
224
225 public ListenableFuture<Void> createDirectory(final String containerName, final String directory) {
226
227 return blobUtils.directoryExists(containerName, directory) ? Futures.immediateFuture((Void) null)
228 : org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() {
229 public Void call() throws Exception {
230 blobUtils.createDirectory(containerName, directory);
231 return null;
232 }
233
234 @Override
235 public String toString() {
236 return "createDirectory(" + containerName + "," + directory + ")";
237 }
238 }), service);
239 }
240
241
242
243
244
245
246
247
248
249
250 @Override
251 public ListenableFuture<Blob> getBlob(String container, String key) {
252 return getBlob(container, key, org.jclouds.blobstore.options.GetOptions.NONE);
253 }
254
255
256
257
258
259
260
261 @Override
262 public ListenableFuture<Void> deleteContainer(final String container) {
263 return org.jclouds.concurrent.Futures.makeListenable(service.submit(new Callable<Void>() {
264
265 public Void call() throws Exception {
266 deleteAndEnsurePathGone(container);
267 return null;
268 }
269
270 @Override
271 public String toString() {
272 return "deleteContainer(" + container + ")";
273 }
274 }), service);
275 }
276
277 protected void deleteAndEnsurePathGone(final String container) {
278 try {
279 if (!Assertions.eventuallyTrue(new Supplier<Boolean>() {
280 public Boolean get() {
281 try {
282 clearContainer(container, recursive());
283 return deleteAndVerifyContainerGone(container);
284 } catch (ContainerNotFoundException e) {
285 return true;
286 }
287 }
288
289 }, 30000)) {
290 throw new IllegalStateException(container + " still exists after deleting!");
291 }
292 } catch (InterruptedException e) {
293 new IllegalStateException(container + " interrupted during deletion!", e);
294 }
295 }
296
297 @Override
298 public ListenableFuture<Set<? extends Location>> listAssignableLocations() {
299 return Futures.<Set<? extends Location>> immediateFuture(locations.get());
300 }
301
302 protected abstract boolean deleteAndVerifyContainerGone(String container);
303
304 }