Removes CopyObjectException in favor of jclouds-standard blobstore exceptions

This commit is contained in:
Zack Shoylev 2015-07-08 15:42:52 -05:00
parent 6945b04243
commit 65b7bdf282
9 changed files with 69 additions and 104 deletions

View File

@ -1,48 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.swift.v1;
import org.jclouds.rest.ResourceNotFoundException;
/**
* Thrown when an object cannot be copied.
*
*
* @see {@link SwiftErrorHandler#handleError(HttpCommand, HttpResponse)}
*/
@SuppressWarnings("serial")
public class CopyObjectException extends ResourceNotFoundException {
private String sourcePath;
private String destinationPath;
public CopyObjectException(String sourcePath, String destinationPath, String message) {
super(String.format("Either the source path '%s' or the destination path '%s' was not found. " +
"(message: %s)", sourcePath, destinationPath, message));
this.sourcePath = sourcePath;
this.destinationPath = destinationPath;
}
public String getSourcePath() {
return sourcePath;
}
public String getDestinationPath() {
return destinationPath;
}
}

View File

@ -32,6 +32,7 @@ import javax.inject.Inject;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobAccess;
import org.jclouds.blobstore.domain.BlobBuilder;
@ -284,6 +285,9 @@ public class RegionScopedSwiftBlobStore implements BlobStore {
}
} else {
SwiftObject metadata = api.getObjectApi(regionId, fromContainer).getWithoutBody(fromName);
if (metadata == null) {
throw new KeyNotFoundException(fromContainer, fromName, "Swift could not find the specified source key");
}
contentMetadata = metadata.getPayload().getContentMetadata();
String contentDisposition = contentMetadata.getContentDisposition();
if (contentDisposition != null) {
@ -306,7 +310,7 @@ public class RegionScopedSwiftBlobStore implements BlobStore {
boolean copied = objectApi.copy(toName, fromContainer, fromName, userMetadata, systemMetadata);
if (!copied) {
throw new RuntimeException("could not copy blob");
throw new KeyNotFoundException(fromContainer, fromName, "Swift could not find the specified key");
}
// TODO: Swift copy object *appends* user metadata, does not overwrite

View File

@ -37,6 +37,8 @@ import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnContainerNotFound;
import org.jclouds.blobstore.BlobStoreFallbacks.FalseOnKeyNotFound;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.http.options.GetOptions;
import org.jclouds.io.Payload;
import org.jclouds.javax.annotation.Nullable;
@ -272,7 +274,7 @@ public interface ObjectApi {
*
* @return {@code true} if the object was successfully copied, {@code false} if not.
*
* @throws org.jclouds.openstack.swift.v1.CopyObjectException if the source or destination container do not exist.
* @throws KeyNotFoundException if the source or destination container do not exist.
*/
@Named("object:copy")
@PUT
@ -302,13 +304,13 @@ public interface ObjectApi {
*
* @return {@code true} if the object was successfully copied, {@code false} if not.
*
* @throws org.jclouds.openstack.swift.v1.CopyObjectException if the source or destination container do not exist.
* @throws KeyNotFoundException if the source or destination container do not exist.
*/
@Named("object:copy")
@PUT
@Path("/{destinationObject}")
@Headers(keys = OBJECT_COPY_FROM, values = "/{sourceContainer}/{sourceObject}")
@Fallback(FalseOnContainerNotFound.class)
@Fallback(FalseOnKeyNotFound.class)
boolean copy(@PathParam("destinationObject") String destinationObject,
@PathParam("sourceContainer") String sourceContainer,
@PathParam("sourceObject") String sourceObject,

View File

@ -27,7 +27,6 @@ import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.swift.v1.CopyObjectException;
import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.InsufficientResourcesException;
@ -55,14 +54,7 @@ public class SwiftErrorHandler implements HttpErrorHandler {
Exception oldException = exception;
String sourcePath = command.getCurrentRequest().getFirstHeaderOrNull(SwiftHeaders.OBJECT_COPY_FROM);
if (sourcePath != null) {
// the path returned here is in the form "/v1/tenant-id/destContainer/destObject"
String path = command.getCurrentRequest().getEndpoint().getPath();
int startOfDestinationPath = path.lastIndexOf("/", path.lastIndexOf("/") - 1);
// get the "/destContainer/destObject" portion of the path
String destinationPath = path.substring(startOfDestinationPath);
exception = new CopyObjectException(sourcePath, destinationPath, message);
exception.initCause(oldException);
exception = new KeyNotFoundException(oldException);
} else if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
String path = command.getCurrentRequest().getEndpoint().getPath();
Matcher matcher = CONTAINER_PATH.matcher(path);

View File

@ -32,9 +32,9 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.http.options.GetOptions;
import org.jclouds.io.Payload;
import org.jclouds.openstack.swift.v1.CopyObjectException;
import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.ObjectList;
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
@ -141,18 +141,17 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
// test exception thrown on bad source name
try {
destApi.copy(destinationObject, badSource, sourceObjectName);
fail("Expected CopyObjectException");
} catch (CopyObjectException e) {
assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObjectName);
assertEquals(e.getDestinationPath(), destinationPath);
}
} catch (KeyNotFoundException e) {
continue;
} finally {
deleteAllObjectsInContainer(regionId, sourceContainer);
containerApi.deleteIfEmpty(sourceContainer);
deleteAllObjectsInContainer(regionId, destinationContainer);
containerApi.deleteIfEmpty(destinationContainer);
}
fail("Expected KeyNotFoundException");
}
}
public void testCopyObjectWithMetadata() throws Exception {
@ -220,18 +219,17 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> {
// test exception thrown on bad source name
try {
destApi.copy(destinationObject, badSource, sourceObjectName);
fail("Expected CopyObjectException");
} catch (CopyObjectException e) {
assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObjectName);
assertEquals(e.getDestinationPath(), destinationPath);
}
} catch (KeyNotFoundException e) {
continue;
} finally {
deleteAllObjectsInContainer(regionId, sourceContainer);
containerApi.deleteIfEmpty(sourceContainer);
deleteAllObjectsInContainer(regionId, destinationContainer);
containerApi.deleteIfEmpty(destinationContainer);
}
fail("Expected KeyNotFoundException");
}
}
public void testList() throws Exception {

View File

@ -33,6 +33,7 @@ import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METAD
import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_REMOVE_METADATA_PREFIX;
import static org.jclouds.util.Strings2.toStringAndClose;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@ -44,11 +45,11 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpResponseException;
import org.jclouds.io.Payload;
import org.jclouds.io.payloads.ByteSourcePayload;
import org.jclouds.openstack.swift.v1.CopyObjectException;
import org.jclouds.openstack.swift.v1.SwiftApi;
import org.jclouds.openstack.swift.v1.domain.ObjectList;
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
@ -485,7 +486,7 @@ public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
}
}
@Test(expectedExceptions = CopyObjectException.class)
@Test(expectedExceptions = KeyNotFoundException.class)
public void testCopyObjectFail() throws InterruptedException, IOException {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
@ -494,7 +495,7 @@ public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
// the following line will throw the CopyObjectException
// the following line will throw the KeyNotFoundException
api.getObjectApi("DFW", "foo").copy("bar.txt", "bogus", "foo.txt");
} finally {
server.shutdown();
@ -529,7 +530,6 @@ public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
}
}
@Test(expectedExceptions = CopyObjectException.class)
public void testCopyObjectWithMetadataFail() throws Exception {
MockWebServer server = mockOpenStackServer();
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
@ -538,7 +538,7 @@ public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
try {
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift");
assertTrue(api.getObjectApi("DFW", "foo")
assertFalse(api.getObjectApi("DFW", "foo")
.copy("bar.txt", "bar", "foo.txt", ImmutableMap.of("someUserHeader", "someUserMetadataValue"),
ImmutableMap.of("Content-Disposition", "attachment; filename=\"fname.ext\"")));
} finally {

View File

@ -27,7 +27,6 @@ import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.swift.v1.CopyObjectException;
import org.jclouds.openstack.swift.v1.reference.SwiftHeaders;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.InsufficientResourcesException;
@ -55,14 +54,7 @@ public class CloudFilesErrorHandler implements HttpErrorHandler {
Exception oldException = exception;
String sourcePath = command.getCurrentRequest().getFirstHeaderOrNull(SwiftHeaders.OBJECT_COPY_FROM);
if (sourcePath != null) {
// the path returned here is in the form "/v1/tenant-id/destContainer/destObject"
String path = command.getCurrentRequest().getEndpoint().getPath();
int startOfDestinationPath = path.lastIndexOf("/", path.lastIndexOf("/") - 1);
// get the "/destContainer/destObject" portion of the path
String destinationPath = path.substring(startOfDestinationPath);
exception = new CopyObjectException(sourcePath, destinationPath, message);
exception.initCause(oldException);
exception = new KeyNotFoundException(oldException);
} else if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
String path = command.getCurrentRequest().getEndpoint().getPath();
Matcher matcher = CONTAINER_PATH.matcher(path);

View File

@ -39,6 +39,7 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.binders.BindMapToHeadersWithPrefix;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.http.functions.ParseETagHeader;
@ -328,7 +329,7 @@ public interface CommonSwiftClient extends Closeable {
/**
* @return True If the object was copied
* @throws CopyObjectException If the object was not copied
* @throws KeyNotFoundException If the object was not copied
* @deprecated This method will be replaced by
* {@link org.jclouds.openstack.swift.v1.features.ObjectApi#copy()}
*/
@ -337,7 +338,7 @@ public interface CommonSwiftClient extends Closeable {
@PUT
@Path("/{destinationContainer}/{destinationObject}")
@Headers(keys = OBJECT_COPY_FROM, values = "/{sourceContainer}/{sourceObject}")
@Fallback(FalseOnContainerNotFound.class)
@Fallback(FalseOnKeyNotFound.class)
boolean copyObject(@PathParam("sourceContainer") String sourceContainer,
@PathParam("sourceObject") String sourceObject,
@PathParam("destinationContainer") String destinationContainer,

View File

@ -47,9 +47,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.ws.rs.core.MediaType;
import com.google.common.hash.Hashing;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobAccess;
import org.jclouds.blobstore.domain.BlobBuilder.PayloadBlobBuilder;
@ -66,8 +66,8 @@ import org.jclouds.blobstore.strategy.internal.MultipartUploadSlicingAlgorithm;
import org.jclouds.crypto.Crypto;
import org.jclouds.encryption.internal.JCECrypto;
import org.jclouds.http.HttpResponseException;
import org.jclouds.io.ContentMetadataBuilder;
import org.jclouds.io.ByteStreams2;
import org.jclouds.io.ContentMetadataBuilder;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.ByteSourcePayload;
@ -90,8 +90,9 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteStreams;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import com.google.common.net.HttpHeaders;
import com.google.common.util.concurrent.ListenableFuture;
@ -983,6 +984,29 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
}
}
@Test(groups = { "integration", "live" }, expectedExceptions = {KeyNotFoundException.class})
public void testCopy404BlobFail() throws Exception {
BlobStore blobStore = view.getBlobStore();
String container = getContainerName();
try {
blobStore.copyBlob(container, "blob", container, "blob2", CopyOptions.NONE);
} finally {
returnContainer(container);
}
}
@Test(groups = { "integration", "live" }, expectedExceptions = {KeyNotFoundException.class})
public void testCopy404BlobMetaFail() throws Exception {
BlobStore blobStore = view.getBlobStore();
String container = getContainerName();
try {
blobStore.copyBlob(container, "blob", container, "blob2",
CopyOptions.builder().userMetadata(ImmutableMap.of("x", "1")).build());
} finally {
returnContainer(container);
}
}
protected void validateMetadata(BlobMetadata metadata) throws IOException {
assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
.getContentType();