Skip to content

Commit b2c46e6

Browse files
committed
Merge pull request #37 from bouncestorage/bulk-delete-fixes
bulk-delete fixes
2 parents 5506115 + 8e03204 commit b2c46e6

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

src/main/java/com/bouncestorage/swiftproxy/v1/AccountResource.java

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818

1919
import static java.util.Objects.requireNonNull;
2020

21+
import static com.google.common.base.Throwables.propagate;
22+
23+
import java.io.BufferedReader;
24+
import java.io.IOException;
25+
import java.io.InputStreamReader;
2126
import java.util.ArrayList;
2227
import java.util.List;
2328
import java.util.Objects;
@@ -37,6 +42,7 @@
3742
import javax.ws.rs.Produces;
3843
import javax.ws.rs.QueryParam;
3944
import javax.ws.rs.WebApplicationException;
45+
import javax.ws.rs.core.Context;
4046
import javax.ws.rs.core.MediaType;
4147
import javax.ws.rs.core.Response;
4248
import javax.xml.bind.annotation.XmlAttribute;
@@ -50,15 +56,18 @@
5056
import com.fasterxml.jackson.annotation.JsonProperty;
5157
import com.fasterxml.jackson.core.JsonProcessingException;
5258
import com.fasterxml.jackson.databind.ObjectMapper;
59+
import com.google.common.collect.Lists;
5360

61+
import org.glassfish.grizzly.http.server.Request;
5462
import org.jclouds.blobstore.BlobStore;
5563
import org.jclouds.blobstore.ContainerNotFoundException;
56-
5764
import org.jclouds.blobstore.domain.StorageMetadata;
65+
import org.jclouds.util.Strings2;
5866

5967
@Singleton
6068
@Path("/v1/{account}")
6169
public final class AccountResource extends BlobStoreResource {
70+
private static final Iterable<Character> skipPathEncoding = Lists.charactersOf("/:;=");
6271

6372
@GET
6473
public Response getAccount(@NotNull @PathParam("account") String account,
@@ -111,42 +120,61 @@ public Response headAccount(@NotNull @PathParam("account") String account,
111120
@Consumes(MediaType.TEXT_PLAIN)
112121
@Produces(MediaType.APPLICATION_JSON)
113122
public BulkDeleteResult bulkDelete(@NotNull @PathParam("account") String account,
114-
@QueryParam("bulk-delete") boolean bulkDelete,
123+
@QueryParam("bulk-delete") String bulkDelete,
115124
@HeaderParam("X-Auth-Token") String authToken,
116-
String objectsList) throws JsonProcessingException {
117-
if (!bulkDelete) {
125+
@Context Request request) throws JsonProcessingException {
126+
if (bulkDelete == null) {
118127
// TODO: Currently this will match the account delete request as well, which we do not implement
119128
throw new WebApplicationException(Response.Status.NOT_IMPLEMENTED);
120129
}
121130

122-
if (objectsList == null) {
123-
return new BulkDeleteResult();
124-
}
125-
String[] objects = objectsList.split("\n");
126131
BlobStore blobStore = getBlobStore(authToken).get();
127132
if (blobStore == null) {
128133
throw new WebApplicationException(Response.Status.BAD_REQUEST);
129134
}
135+
136+
BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
137+
String line;
138+
ArrayList<String> objects = new ArrayList<>();
139+
140+
boolean isTransient = blobStore.getContext().unwrap().getId().equals("transient");
141+
try {
142+
while ((line = in.readLine()) != null) {
143+
if (isTransient) {
144+
// jclouds does not escape things correctly
145+
line = Strings2.urlEncode(line, skipPathEncoding);
146+
}
147+
objects.add(line);
148+
}
149+
} catch (IOException e) {
150+
throw propagate(e);
151+
}
152+
130153
BulkDeleteResult result = new BulkDeleteResult();
131154
for (String objectContainer : objects) {
132155
try {
133-
if (!objectContainer.startsWith("/")) {
134-
result.errors.add(objectContainer);
135-
continue;
156+
if (objectContainer.startsWith("/")) {
157+
objectContainer = objectContainer.substring(1);
136158
}
137-
int separatorIndex = objectContainer.indexOf("/", 1);
159+
int separatorIndex = objectContainer.indexOf('/');
138160
if (separatorIndex < 0) {
139161
blobStore.deleteContainer(objectContainer.substring(1));
140162
result.numberDeleted += 1;
141163
continue;
142164
}
143-
String container = objectContainer.substring(1, separatorIndex);
165+
String container = objectContainer.substring(0, separatorIndex);
144166
String object = objectContainer.substring(separatorIndex + 1);
145-
blobStore.removeBlob(container, object);
146-
result.numberDeleted += 1;
167+
168+
if (!blobStore.blobExists(container, object)) {
169+
result.numberNotFound += 1;
170+
} else {
171+
blobStore.removeBlob(container, object);
172+
result.numberDeleted += 1;
173+
}
147174
} catch (ContainerNotFoundException e) {
148175
result.numberNotFound += 1;
149176
} catch (Exception e) {
177+
e.printStackTrace();
150178
result.errors.add(objectContainer);
151179
}
152180
}

src/test/java/com/bouncestorage/swiftproxy/v1/AccountResourceTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ public void testBulkDelete() throws Exception {
8282

8383
String[] removeObjects = {"/test/bar", "/test"};
8484
Response response = target.path(TestUtils.ACCOUNT_PATH)
85-
.queryParam("bulk-delete", "true")
85+
// swift actually sends ?bulk-delete and this sends ?bulk-delete=, but
86+
// that's the closest we can get
87+
.queryParam("bulk-delete", "")
8688
.request()
8789
.header("X-Auth-Token", authToken)
8890
.post(Entity.entity(Joiner.on("\n").join(removeObjects), MediaType.TEXT_PLAIN));

0 commit comments

Comments
 (0)