Skip to content

Commit

Permalink
Azure#84 getBlobReferenceFromServer
Browse files Browse the repository at this point in the history
  • Loading branch information
emgerner-msft committed May 31, 2016
1 parent 6323817 commit 21650f7
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
2016.x.x Version 4.3.0
* Added support for getBlobReferenceFromServer methods on CloudBlobContainer to support retrieving a blob without knowing its type.

2016.04.07 Version 4.2.0
* Added support for setting a library-wide proxy. The default proxy can be set on OperationContext.
* Added support in Page Blob for getting a list of differing page ranges between snapshot versions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ public static void assertAreEqual(CloudBlob blob1, CloudBlob blob2) throws URISy
}
else {
assertNotNull(blob2);
assertEquals(blob1.getClass(), blob2.getClass());
assertEquals(blob1.getUri(), blob2.getUri());
assertEquals(blob1.getSnapshotID(), blob2.getSnapshotID());
assertEquals(blob1.isSnapshot(), blob2.isSnapshot());
Expand All @@ -399,6 +400,7 @@ public static void assertAreEqual(BlobProperties prop1, BlobProperties prop2) {
}
else {
assertNotNull(prop2);
assertEquals(prop1.getBlobType(), prop2.getBlobType());
assertEquals(prop1.getCacheControl(), prop2.getCacheControl());
assertEquals(prop1.getContentDisposition(), prop2.getContentDisposition());
assertEquals(prop1.getContentEncoding(), prop2.getContentEncoding());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
Expand All @@ -41,6 +42,7 @@
import com.microsoft.azure.storage.ResultContinuation;
import com.microsoft.azure.storage.ResultSegment;
import com.microsoft.azure.storage.SendingRequestEvent;
import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageEvent;
import com.microsoft.azure.storage.StorageException;
Expand Down Expand Up @@ -134,6 +136,86 @@ public void testCloudBlobContainerReference() throws StorageException, URISyntax
.toString());
}

@Test
@Category({ DevFabricTests.class, DevStoreTests.class })
public void testCloudBlobContainerReferenceFromServer() throws StorageException, URISyntaxException, IOException {
this.container.create();

CloudBlob blob = BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, null, 1024, null);
blob.getProperties().setContentType("application/octet-stream");
blob.getProperties().setLength(1024);

CloudBlob blobRef = this.container.getBlobReferenceFromServer(blob.getName());
BlobTestHelper.assertAreEqual(blob, blobRef);

blob = BlobTestHelper.uploadNewBlob(this.container, BlobType.PAGE_BLOB, null, 1024, null);
blob.getProperties().setContentType("application/octet-stream");
blob.getProperties().setLength(1024);

blobRef = this.container.getBlobReferenceFromServer(blob.getName());
BlobTestHelper.assertAreEqual(blob, blobRef);

blob = BlobTestHelper.uploadNewBlob(this.container, BlobType.APPEND_BLOB, null, 1024, null);
blob.getProperties().setContentType("application/octet-stream");
blob.getProperties().setLength(1024);

blobRef = this.container.getBlobReferenceFromServer(blob.getName());
BlobTestHelper.assertAreEqual(blob, blobRef);
}

@Test
@Category({ DevFabricTests.class, DevStoreTests.class })
public void testCloudBlobContainerReferenceFromServerSnapshot() throws StorageException, URISyntaxException,
IOException {
this.container.create();

CloudBlob blob = BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, null, 1024, null);
CloudBlob snapshot = blob.createSnapshot();
snapshot.getProperties().setContentType("application/octet-stream");
snapshot.getProperties().setLength(1024);

CloudBlob blobRef = this.container.getBlobReferenceFromServer(snapshot.getName(), snapshot.getSnapshotID(),
null, null, null);
BlobTestHelper.assertAreEqual(snapshot, blobRef);
}

@Test
@Category({ DevFabricTests.class, DevStoreTests.class })
public void testCloudBlobContainerReferenceFromServerSAS() throws StorageException, URISyntaxException,
IOException, InvalidKeyException {
this.container.create();
CloudBlob blob = BlobTestHelper.uploadNewBlob(this.container, BlobType.BLOCK_BLOB, null, 1024, null);

SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE, 10);
policy.setSharedAccessExpiryTime(now.getTime());
policy.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ));
String token = this.container.generateSharedAccessSignature(policy, null);

CloudBlobContainer containerSAS = new CloudBlobContainer(this.container.getStorageUri(),
new StorageCredentialsSharedAccessSignature(token));
CloudBlob blobRef = containerSAS.getBlobReferenceFromServer(blob.getName());
assertEquals(blob.getClass(), blobRef.getClass());
assertEquals(blob.getUri(), blobRef.getUri());
}

@Test
@Category({ DevFabricTests.class, DevStoreTests.class })
public void testCloudBlobContainerReferenceFromServerMissingBlob() throws StorageException, URISyntaxException,
IOException {
this.container.create();

String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("missing");

try {
this.container.getBlobReferenceFromServer(blobName);
fail("Get reference from server should fail.");
} catch (StorageException ex) {
assertEquals(404, ex.getHttpStatusCode());
}
}

/**
* Create a container
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,139 @@ public CloudBlobDirectory getDirectoryReference(String directoryName) throws URI

return new CloudBlobDirectory(address, directoryName, this.blobServiceClient, this);
}


/**
* Gets a reference to a blob in this container. The blob must already exist on the service.
*
* Unlike the other get*Reference methods, this method does a service request to retrieve the blob's metadata and
* properties. The returned blob may be used directly as a CloudBlob or cast using either instanceof or
* getProperties().getBlobType() to determine its subtype.
*
* @param blobName
* A <code>String</code> that represents the name of the blob.
*
* @return A {@link CloudBlob} object that represents a reference to the specified blob.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
@DoesServiceRequest
public final CloudBlob getBlobReferenceFromServer(final String blobName) throws URISyntaxException, StorageException {
return this.getBlobReferenceFromServer(blobName, null, null, null, null);
}

/**
* Gets a reference to a blob in this container. The blob must already exist on the service.
*
* Unlike the other get*Reference methods, this method does a service request to retrieve the blob's metadata and
* properties. The returned blob may be used directly as a CloudBlob or cast using either instanceof or
* getProperties().getBlobType() to determine its subtype.
*
* @param blobName
* A <code>String</code> that represents the name of the blob.
* @param snapshotID
* A <code>String</code> that represents the snapshot ID of the blob.
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the blob.
* @param options
* A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
* <code>null</code> will use the default request options from the associated service client (
* {@link CloudBlobClient}).
* @param opContext
* An {@link OperationContext} object that represents the context for the current operation. This object
* is used to track requests to the storage service, and to provide additional runtime information about
* the operation.
*
* @return A {@link CloudBlob} object that represents a reference to the specified blob.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
@DoesServiceRequest
public final CloudBlob getBlobReferenceFromServer(final String blobName, final String snapshotID,
AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext)
throws URISyntaxException, StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);

StorageUri blobUri = PathUtility.appendPathToUri(this.getStorageUri(), blobName);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.getBlobReferenceFromServerImpl(blobName, blobUri, snapshotID, accessCondition, options), options.getRetryPolicyFactory(), opContext);
}

private StorageRequest<CloudBlobClient, CloudBlobContainer, CloudBlob> getBlobReferenceFromServerImpl(
final String blobName, final StorageUri blobUri, final String snapshotID, final AccessCondition accessCondition,
final BlobRequestOptions options) {
final StorageRequest<CloudBlobClient, CloudBlobContainer, CloudBlob> getRequest = new StorageRequest<CloudBlobClient, CloudBlobContainer, CloudBlob>(
options, this.getStorageUri()) {

@Override
public void setRequestLocationMode() {
this.setRequestLocationMode(RequestLocationMode.PRIMARY_OR_SECONDARY);
}

@Override
public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer container,
OperationContext context) throws Exception {
StorageUri transformedblobUri = CloudBlobContainer.this.getServiceClient().getCredentials().transformUri(blobUri, context);
return BlobRequest.getBlobProperties(transformedblobUri.getUri(this.getCurrentLocation()), options, context, accessCondition, snapshotID);
}

@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}

@Override
public CloudBlob preProcessResponse(CloudBlobContainer container, CloudBlobClient client, OperationContext context)
throws Exception {
if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
this.setNonExceptionedRetryableFailure(true);
return null;
}

// Set attributes
final BlobAttributes retrievedAttributes = BlobResponse.getBlobAttributes(this.getConnection(),
blobUri, snapshotID);

CloudBlob blob;
switch (retrievedAttributes.getProperties().getBlobType()) {
case APPEND_BLOB:
blob = container.getAppendBlobReference(blobName, snapshotID);
break;

case BLOCK_BLOB:
blob = container.getBlockBlobReference(blobName, snapshotID);
break;

case PAGE_BLOB:
blob = container.getPageBlobReference(blobName, snapshotID);
break;

default:
throw new StorageException(StorageErrorCodeStrings.INCORRECT_BLOB_TYPE,
SR.INVALID_RESPONSE_RECEIVED, Constants.HeaderConstants.HTTP_UNUSED_306, null, null);
}

blob.properties = retrievedAttributes.getProperties();
blob.metadata = retrievedAttributes.getMetadata();

return blob;
}
};

return getRequest;
}


/**
* Returns the metadata for the container. This value is initialized with the metadata from the queue by a call to
* {@link #downloadAttributes}, and is set on the queue with a call to {@link #uploadMetadata}.
Expand Down

0 comments on commit 21650f7

Please sign in to comment.