FileServiceProperties
objects to ensure they match.
+ *
+ * @param original
+ * The FileServiceProperties
used as a point of comparison
+ * @param target
+ * The generated FileServiceProperties
, which should match the original
+ */
+ private static void assertFileServicePropertiesAreEqual(FileServiceProperties original, FileServiceProperties target) {
+ if (original == null && target == null) {
+ return;
+ } else {
+ assertNotNull(original);
+ assertNotNull(target);
+ }
+
+ if (original.getCors() != null && target.getCors() != null) {
+ assertEquals(original.getCors().getCorsRules().size(), target.getCors().getCorsRules().size());
+
+ // Check that rules are equal and in the same order.
+ for (int i = 0; i < original.getCors().getCorsRules().size(); i++) {
+ CorsRule ruleOriginal = original.getCors().getCorsRules().get(i);
+ CorsRule ruleTarget = target.getCors().getCorsRules().get(i);
+
+ assertTrue(ruleOriginal.getAllowedOrigins().size() == ruleTarget.getAllowedOrigins().size());
+ assertTrue(ruleOriginal.getAllowedOrigins().containsAll(ruleTarget.getAllowedOrigins()));
+
+ assertTrue(ruleOriginal.getExposedHeaders().size() == ruleTarget.getExposedHeaders().size());
+ assertTrue(ruleOriginal.getExposedHeaders().containsAll(ruleTarget.getExposedHeaders()));
+
+ assertTrue(ruleOriginal.getAllowedHeaders().size() == ruleTarget.getAllowedHeaders().size());
+ assertTrue(ruleOriginal.getAllowedHeaders().containsAll(ruleTarget.getAllowedHeaders()));
+
+ assertTrue(ruleOriginal.getAllowedMethods().equals(ruleTarget.getAllowedMethods()));
+
+ assertTrue(ruleOriginal.getMaxAgeInSeconds() == ruleTarget.getMaxAgeInSeconds());
+ }
+ }
+ else {
+ assertNull(original.getCors());
+ assertNull(target.getCors());
+ }
+ }
}
diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java
index 9e7c496d96c3e..f2ccccd3bd902 100644
--- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java
+++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageAccountTests.java
@@ -64,30 +64,31 @@ public void testStorageCredentialsSharedKey() throws URISyntaxException, Storage
URI testUri = new URI("http://test/abc?querya=1");
assertEquals(testUri, cred.transformUri(testUri));
- assertEquals(ACCOUNT_KEY, cred.getCredentials().exportBase64EncodedKey());
+ assertEquals(ACCOUNT_KEY, cred.exportBase64EncodedKey());
byte[] dummyKey = { 0, 1, 2 };
String base64EncodedDummyKey = Base64.encode(dummyKey);
cred = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, base64EncodedDummyKey);
- assertEquals(base64EncodedDummyKey, cred.getCredentials().exportBase64EncodedKey());
+ assertEquals(base64EncodedDummyKey, cred.exportBase64EncodedKey());
dummyKey[0] = 3;
base64EncodedDummyKey = Base64.encode(dummyKey);
cred = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, base64EncodedDummyKey);
- assertEquals(base64EncodedDummyKey, cred.getCredentials().exportBase64EncodedKey());
+ assertEquals(base64EncodedDummyKey, cred.exportBase64EncodedKey());
}
@Test
public void testStorageCredentialsSAS() throws URISyntaxException, StorageException {
- String token = "?sig=1&api-version=2014-02-14&sp=abcde";
+ String token = "?sig=1&sp=abcde&api-version=" + Constants.HeaderConstants.TARGET_STORAGE_VERSION;
StorageCredentialsSharedAccessSignature cred = new StorageCredentialsSharedAccessSignature(token);
assertNull(cred.getAccountName());
- URI testUri = new URI("http://test/abc");
- assertEquals(testUri + token, cred.transformUri(testUri).toString());
+ URI testUri = new URI("http://test/abc" + token);
+ TestHelper.assertURIsEqual(testUri, cred.transformUri(testUri), true);
testUri = new URI("http://test/abc?query=a&query2=b");
- String expectedUri = "http://test/abc?sig=1&api-version=2014-02-14&query=a&sp=abcde&query2=b";
- assertEquals(expectedUri, cred.transformUri(testUri).toString());
+ URI expectedUri = new URI("http://test/abc?sig=1&query=a&sp=abcde&query2=b&api-version="
+ + Constants.HeaderConstants.TARGET_STORAGE_VERSION);
+ TestHelper.assertURIsEqual(expectedUri, cred.transformUri(testUri), true);
}
@Test
@@ -96,36 +97,30 @@ public void testStorageCredentialsEmptyKeyValue() throws URISyntaxException, Inv
String emptyKeyConnectionString = String.format(Locale.US,
"DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=", ACCOUNT_NAME);
- StorageCredentialsAccountAndKey credentials1 = new StorageCredentialsAccountAndKey(ACCOUNT_NAME,
- emptyKeyValueAsString);
- assertEquals(ACCOUNT_NAME, credentials1.getAccountName());
- assertEquals(emptyKeyValueAsString, Base64.encode(credentials1.getCredentials().exportKey()));
-
- CloudStorageAccount account1 = new CloudStorageAccount(credentials1, true);
- assertEquals(emptyKeyConnectionString, account1.toString(true));
- assertNotNull(account1.getCredentials());
- assertEquals(ACCOUNT_NAME, account1.getCredentials().getAccountName());
- assertEquals(emptyKeyValueAsString,
- Base64.encode(((StorageCredentialsAccountAndKey) (account1.getCredentials())).getCredentials()
- .exportKey()));
-
- CloudStorageAccount account2 = CloudStorageAccount.parse(emptyKeyConnectionString);
- assertEquals(emptyKeyConnectionString, account2.toString(true));
- assertNotNull(account2.getCredentials());
- assertEquals(ACCOUNT_NAME, account2.getCredentials().getAccountName());
- assertEquals(emptyKeyValueAsString,
- Base64.encode(((StorageCredentialsAccountAndKey) (account2.getCredentials())).getCredentials()
- .exportKey()));
+ try {
+ new StorageCredentialsAccountAndKey(ACCOUNT_NAME, emptyKeyValueAsString);
+ fail("Did not hit expected exception");
+ }
+ catch (IllegalArgumentException ex) {
+ assertEquals(SR.INVALID_KEY, ex.getMessage());
+ }
- StorageCredentialsAccountAndKey credentials2 = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, ACCOUNT_KEY);
- assertEquals(ACCOUNT_NAME, credentials2.getAccountName());
- assertEquals(ACCOUNT_KEY, Base64.encode(credentials2.getCredentials().exportKey()));
+ try {
+ CloudStorageAccount.parse(emptyKeyConnectionString);
+ fail("Did not hit expected exception");
+ }
+ catch (IllegalArgumentException ex) {
+ assertEquals(SR.INVALID_CONNECTION_STRING, ex.getMessage());
+ }
- byte[] emptyKeyValueAsByteArray = new byte[0];
- StorageCredentialsAccountAndKey credentials3 = new StorageCredentialsAccountAndKey(ACCOUNT_NAME,
- emptyKeyValueAsByteArray);
- assertEquals(ACCOUNT_NAME, credentials3.getAccountName());
- assertEquals(Base64.encode(emptyKeyValueAsByteArray), Base64.encode(credentials3.getCredentials().exportKey()));
+ try {
+ byte[] emptyKeyValueAsByteArray = new byte[0];
+ new StorageCredentialsAccountAndKey(ACCOUNT_NAME, emptyKeyValueAsByteArray);
+ fail("Did not hit expected exception");
+ }
+ catch (IllegalArgumentException ex) {
+ assertEquals(SR.INVALID_KEY, ex.getMessage());
+ }
}
@Test
@@ -136,13 +131,13 @@ public void testStorageCredentialsNullKeyValue() {
new StorageCredentialsAccountAndKey(ACCOUNT_NAME, nullKeyValueAsString);
fail("Did not hit expected exception");
}
- catch (NullPointerException ex) {
- // assertEquals(SR.KEY_NULL, ex.getMessage());
+ catch (IllegalArgumentException ex) {
+ assertEquals(SR.INVALID_KEY, ex.getMessage());
}
StorageCredentialsAccountAndKey credentials2 = new StorageCredentialsAccountAndKey(ACCOUNT_NAME, ACCOUNT_KEY);
assertEquals(ACCOUNT_NAME, credentials2.getAccountName());
- assertEquals(ACCOUNT_KEY, Base64.encode(credentials2.getCredentials().exportKey()));
+ assertEquals(ACCOUNT_KEY, Base64.encode(credentials2.exportKey()));
byte[] nullKeyValueAsByteArray = null;
try {
@@ -150,7 +145,7 @@ public void testStorageCredentialsNullKeyValue() {
fail("Did not hit expected exception");
}
catch (IllegalArgumentException ex) {
- assertEquals(SR.KEY_NULL, ex.getMessage());
+ assertEquals(SR.INVALID_KEY, ex.getMessage());
}
}
@@ -603,10 +598,10 @@ public void testCloudStorageAccountExportKey() throws InvalidKeyException, URISy
String accountString = "BlobEndpoint=http://blobs/;AccountName=test;AccountKey=" + accountKeyString;
CloudStorageAccount account = CloudStorageAccount.parse(accountString);
StorageCredentialsAccountAndKey accountAndKey = (StorageCredentialsAccountAndKey) account.getCredentials();
- String key = accountAndKey.getCredentials().getKey().getBase64EncodedKey();
+ String key = accountAndKey.exportBase64EncodedKey();
assertEquals(accountKeyString, key);
- byte[] keyBytes = accountAndKey.getCredentials().exportKey();
+ byte[] keyBytes = accountAndKey.exportKey();
byte[] expectedKeyBytes = Base64.decode(accountKeyString);
assertArrayEquals(expectedKeyBytes, keyBytes);
}
diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java
index 589e57464d2f4..f067a0c30d8be 100644
--- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java
+++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/StorageUriTests.java
@@ -193,7 +193,7 @@ public void testBlobTypesWithStorageUri() throws StorageException, URISyntaxExce
assertEquals(containerUri.getPrimaryUri(), container.getUri());
assertEquals(endpoint, container.getServiceClient().getStorageUri());
- container = new CloudBlobContainer(containerUri, client);
+ container = new CloudBlobContainer(containerUri, client.getCredentials());
assertEquals(containerUri, container.getStorageUri());
assertEquals(containerUri.getPrimaryUri(), container.getUri());
assertEquals(endpoint, container.getServiceClient().getStorageUri());
@@ -228,7 +228,7 @@ public void testBlobTypesWithStorageUri() throws StorageException, URISyntaxExce
assertEquals(containerUri, blockBlob.getContainer().getStorageUri());
assertEquals(endpoint, blockBlob.getServiceClient().getStorageUri());
- blockBlob = new CloudBlockBlob(blobUri, null, client);
+ blockBlob = new CloudBlockBlob(blobUri, client.getCredentials());
assertEquals(blobUri, blockBlob.getStorageUri());
assertEquals(blobUri.getPrimaryUri(), blockBlob.getUri());
assertEquals(subdirectoryUri, blockBlob.getParent().getStorageUri());
@@ -242,7 +242,7 @@ public void testBlobTypesWithStorageUri() throws StorageException, URISyntaxExce
assertEquals(containerUri, pageBlob.getContainer().getStorageUri());
assertEquals(endpoint, pageBlob.getServiceClient().getStorageUri());
- pageBlob = new CloudPageBlob(blobUri, null, client);
+ pageBlob = new CloudPageBlob(blobUri, client.getCredentials());
assertEquals(blobUri, pageBlob.getStorageUri());
assertEquals(blobUri.getPrimaryUri(), pageBlob.getUri());
assertEquals(subdirectoryUri, pageBlob.getParent().getStorageUri());
@@ -268,7 +268,7 @@ public void testQueueTypesWithStorageUri() throws URISyntaxException, StorageExc
assertEquals(queueUri.getPrimaryUri(), queue.getUri());
assertEquals(endpoint, queue.getServiceClient().getStorageUri());
- queue = new CloudQueue(queueUri, client);
+ queue = new CloudQueue(queueUri, client.getCredentials());
assertEquals(queueUri, queue.getStorageUri());
assertEquals(queueUri.getPrimaryUri(), queue.getUri());
assertEquals(endpoint, queue.getServiceClient().getStorageUri());
@@ -292,7 +292,7 @@ public void testTableTypesWithStorageUri() throws URISyntaxException, StorageExc
assertEquals(tableUri.getPrimaryUri(), table.getUri());
assertEquals(endpoint, table.getServiceClient().getStorageUri());
- table = new CloudTable(tableUri, client);
+ table = new CloudTable(tableUri, client.getCredentials());
assertEquals(tableUri, table.getStorageUri());
assertEquals(tableUri.getPrimaryUri(), table.getUri());
assertEquals(endpoint, table.getServiceClient().getStorageUri());
diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestHelper.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestHelper.java
index 8bb80cc859470..3e75ec214e735 100644
--- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestHelper.java
+++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestHelper.java
@@ -14,20 +14,22 @@
*/
package com.microsoft.azure.storage;
+import static org.junit.Assert.*;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Random;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import junit.framework.Assert;
-
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -46,36 +48,26 @@ public class TestHelper {
private static StorageCredentialsAccountAndKey credentials;
private static CloudStorageAccount account;
- @SuppressWarnings("deprecation")
- private final static AuthenticationScheme defaultAuthenticationScheme = AuthenticationScheme.SHAREDKEYFULL;
private final static boolean enableFiddler = true;
private final static boolean requireSecondaryEndpoint = false;
- @SuppressWarnings("deprecation")
public static CloudBlobClient createCloudBlobClient() throws StorageException {
CloudBlobClient client = getAccount().createCloudBlobClient();
- client.setAuthenticationScheme(defaultAuthenticationScheme);
return client;
}
- @SuppressWarnings("deprecation")
public static CloudFileClient createCloudFileClient() throws StorageException {
CloudFileClient client = getAccount().createCloudFileClient();
- client.setAuthenticationScheme(defaultAuthenticationScheme);
return client;
}
- @SuppressWarnings("deprecation")
public static CloudQueueClient createCloudQueueClient() throws StorageException {
CloudQueueClient client = getAccount().createCloudQueueClient();
- client.setAuthenticationScheme(defaultAuthenticationScheme);
return client;
}
- @SuppressWarnings("deprecation")
public static CloudTableClient createCloudTableClient() throws StorageException {
CloudTableClient client = getAccount().createCloudTableClient();
- client.setAuthenticationScheme(defaultAuthenticationScheme);
return client;
}
@@ -103,13 +95,13 @@ public static ByteArrayInputStream getRandomDataStream(int length) {
public static void assertStreamsAreEqual(ByteArrayInputStream src, ByteArrayInputStream dst) {
dst.reset();
src.reset();
- Assert.assertEquals(src.available(), dst.available());
+ assertEquals(src.available(), dst.available());
while (src.available() > 0) {
- Assert.assertEquals(src.read(), dst.read());
+ assertEquals(src.read(), dst.read());
}
- Assert.assertFalse(dst.available() > 0);
+ assertFalse(dst.available() > 0);
}
public static void assertStreamsAreEqualAtIndex(ByteArrayInputStream src, ByteArrayInputStream dst, int srcIndex,
@@ -125,8 +117,29 @@ public static void assertStreamsAreEqualAtIndex(ByteArrayInputStream src, ByteAr
dst.read(destBuffer);
for (int i = 0; i < length; i++) {
- Assert.assertEquals(src.read(), dst.read());
+ assertEquals(src.read(), dst.read());
+ }
+ }
+
+ public static void assertURIsEqual(URI expected, URI actual, boolean ignoreQueryOrder) {
+ if (expected == null) {
+ assertEquals(null, actual);
}
+
+ assertEquals(expected.getScheme(), actual.getScheme());
+ assertEquals(expected.getAuthority(), actual.getAuthority());
+ assertEquals(expected.getPath(), actual.getPath());
+ assertEquals(expected.getFragment(), actual.getFragment());
+
+ ArrayList+ * Setting this access condition modifies the request to include the HTTP If-Match conditional header. + *
+ * For more information, see Specifying Conditional Headers
+ * for Blob Service Operations.
+ *
+ * @return An AccessCondition
object that represents the if exists condition.
+ */
+ public static AccessCondition generateIfExistsCondition() {
+ AccessCondition retCondition = new AccessCondition();
+ retCondition.setIfMatch("*");
+ return retCondition;
+ }
+
+ /**
+ * Returns an access condition such that an operation will be performed only if the resource does not exist on the
+ * service.
+ *
+ * Setting this access condition modifies the request to include the HTTP If-None-Match conditional header. + *
+ * For more information, see Specifying Conditional Headers
+ * for Blob Service Operations.
+ *
+ * @return An AccessCondition
object that represents the if not exists condition.
+ */
+ public static AccessCondition generateIfNotExistsCondition() {
+ AccessCondition retCondition = new AccessCondition();
+ retCondition.setIfNoneMatch("*");
+ return retCondition;
+ }
private String leaseID = null;
@@ -223,7 +256,17 @@ public static AccessCondition generateLeaseCondition(final String leaseID) {
* Represents the ifSequenceNumberEqual type. Used only for page blob operations.
*/
private Long ifSequenceNumberEqual = null;
-
+
+ /**
+ * Represents the ifMaxSizeLessThanOrEqual type. Used only for append blob operations.
+ */
+ private Long ifMaxSizeLessThanOrEqual = null;
+
+ /**
+ * Represents the ifAppendPositionEqual type. Used only for append blob operations.
+ */
+ private Long ifAppendPositionEqual = null;
+
/**
* Creates an instance of the AccessCondition
class.
*/
@@ -297,6 +340,28 @@ public void applySourceConditionToRequest(final HttpURLConnection request) {
}
}
+ /**
+ * RESERVED FOR INTERNAL USE. Applies the access condition to the request.
+ *
+ * @param request
+ * A java.net.HttpURLConnection
object that represents the request to which the condition is
+ * being applied.
+ *
+ * @throws StorageException
+ * If there is an error parsing the date value of the access condition.
+ */
+ public void applyAppendConditionToRequest(final HttpURLConnection request) {
+ if (this.ifMaxSizeLessThanOrEqual != null) {
+ request.setRequestProperty(Constants.HeaderConstants.IF_MAX_SIZE_LESS_THAN_OR_EQUAL,
+ this.ifMaxSizeLessThanOrEqual.toString());
+ }
+
+ if (this.ifAppendPositionEqual != null) {
+ request.setRequestProperty(Constants.HeaderConstants.IF_APPEND_POSITION_EQUAL_HEADER,
+ this.ifAppendPositionEqual.toString());
+ }
+ }
+
/**
* RESERVED FOR INTERNAL USE. Applies the lease access condition to the request.
*
@@ -337,6 +402,17 @@ public void applySequenceConditionToRequest(final HttpURLConnection request) {
}
}
+ /**
+ * Gets the value for a conditional header used only for append operations. A number indicating the byte offset to check for.
+ * The append will succeed only if the end position is equal to this number.
+ *
+ * @return The append position number, or null
if no condition exists.
+ */
+ public Long getIfAppendPositionEqual()
+ {
+ return ifAppendPositionEqual;
+ }
+
/**
* Gets the ETag when the If-Match condition is set.
*
@@ -346,6 +422,17 @@ public String getIfMatch() {
return this.ifMatchETag;
}
+ /**
+ * Gets the value for a conditional header used only for append operations. A number that indicates the maximum length in
+ * bytes to restrict the blob to when committing the block.
+ *
+ * @return The maximum size, or null
if no condition exists.
+ */
+ public Long getIfMaxSizeLessThanOrEqual()
+ {
+ return ifMaxSizeLessThanOrEqual;
+ }
+
/**
* Gets the If-Modified-Since date.
*
@@ -412,6 +499,18 @@ public Long getIfSequenceNumberEqual() {
return this.ifSequenceNumberEqual;
}
+ /**
+ * Sets the value for a conditional header used only for append operations. A number indicating the byte offset to check for.
+ * The append will succeed only if the end position is equal to this number.
+ *
+ * @param ifAppendPositionEqual
+ * The append position number, or null
if no condition exists.
+ */
+ public void setIfAppendPositionEqual(Long ifAppendPositionEqual)
+ {
+ this.ifAppendPositionEqual = ifAppendPositionEqual;
+ }
+
/**
* Sets the ETag for the If-Match condition.
*
@@ -421,6 +520,18 @@ public Long getIfSequenceNumberEqual() {
public void setIfMatch(String etag) {
this.ifMatchETag = normalizeEtag(etag);
}
+
+ /**
+ * Sets the value for a conditional header used only for append operations. A number that indicates the maximum length in
+ * bytes to restrict the blob to when committing the block.
+ *
+ * @param ifMaxSizeLessThanOrEqual
+ * The maximum size, or null
if no condition exists.
+ */
+ public void setIfMaxSizeLessThanOrEqual(Long ifMaxSizeLessThanOrEqual)
+ {
+ this.ifMaxSizeLessThanOrEqual = ifMaxSizeLessThanOrEqual;
+ }
/**
* Sets the If-Modified-Since date.
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/CloudStorageAccount.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/CloudStorageAccount.java
index a97a79025fa97..df3b347ea4192 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/CloudStorageAccount.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/CloudStorageAccount.java
@@ -29,6 +29,7 @@
import com.microsoft.azure.storage.core.StorageCredentialsHelper;
import com.microsoft.azure.storage.core.Utility;
import com.microsoft.azure.storage.file.CloudFileClient;
+import com.microsoft.azure.storage.queue.CloudQueue;
import com.microsoft.azure.storage.queue.CloudQueueClient;
import com.microsoft.azure.storage.table.CloudTable;
import com.microsoft.azure.storage.table.CloudTableClient;
@@ -212,8 +213,8 @@ public static CloudStorageAccount getDevelopmentStorageAccount(final URI proxyUr
* connection string format.
*
* Note that while a connection string may include a SAS token, it is often easier to use the
- * {@link CloudBlobContainer#CloudBlobContainer(URI)}, {@link CloudBlobContainer#CloudQueue(URI)},
- * {@link CloudTable#CloudBlobContainer(URI)} constructors directly. To do this, create a
+ * {@link CloudBlobContainer#CloudBlobContainer(URI)}, {@link CloudQueue#CloudQueue(URI)},
+ * {@link CloudTable#CloudTable(URI)} constructors directly. To do this, create a
* {@link StorageCredentialsSharedAccessSignature#StorageCredentialsSharedAccessSignature(String)} object with your
* SAS token, use the {@link StorageCredentialsSharedAccessSignature#transformUri(URI)} method on the container,
* queue, or table URI, and then use that URI to construct the object.
@@ -241,12 +242,9 @@ public static CloudStorageAccount parse(final String connectionString) throws UR
// 2 Validate General Settings rules,
// - only setting value per key
// - setting must have value.
- // - One special case to this rule - the account key can be empty.
for (final Entry
- * The server timeout interval begins at the time that the complete request has been received by the service, and
- * the server begins processing the response. If the timeout interval elapses before the response is returned to the
- * client, the operation times out. The timeout interval resets with each retry, if the request is retried.
- *
- * You can change this value on the service client by setting this property, so that all subsequent requests made
- * via the service client will use the new timeout interval. You can also change this value for an individual
- * request, by setting the {@link RequestOptions#setTimeoutIntervalInMs(Integer)} property.
- *
- * @param timeoutInMs
- * The timeout, in milliseconds, to use when making requests to the storage service.
- *
- * @deprecated use {@link #getDefaultRequestOptions().setTimeoutIntervalInMs()} instead.
- */
- @Deprecated
- public final void setTimeoutInMs(final int timeoutInMs) {
- this.getDefaultRequestOptions().setTimeoutIntervalInMs(timeoutInMs);
- }
-
- /**
- * Sets the maximum execution time to use when making requests to the storage service.
- *
- * The maximum execution time interval begins at the time that the client begins building the request. The maximum
- * execution time is checked intermittently while uploading data, downloading data, and before executing retries.
- * The service will continue to upload, download, and retry until the maximum execution time is reached. At that
- * time, any partial uploads or downloads will be cancelled and an exception will be thrown.
- *
- * The default maximum execution time is null, indicating no maximum time. You can change this value on the service
- * client by setting this property, so that all subsequent requests made via the service client will use the new
- * maximum execution time. You can also change this value for an individual request, by setting the
- * {@link RequestOptions#setMaximumExecutionTimeInMs(Integer)} property.
- *
- * @param maximumExecutionTimeInMs
- * The maximum execution time, in milliseconds, to use when making service requests.
- *
- * @deprecated use {@link #getDefaultRequestOptions().setMaximumExecutionTimeInMs()} instead.
- */
- @Deprecated
- public void setMaximumExecutionTimeInMs(Integer maximumExecutionTimeInMs) {
- this.getDefaultRequestOptions().setMaximumExecutionTimeInMs(maximumExecutionTimeInMs);
- }
-
/**
* Gets the {@link RequestOptions} that is used for requests associated with this
- * The {@link AccessCondition#ifMatch} and {@link AccessCondition#ifNoneMatch} methods take an ETag value and return
- * an {@link AccessCondition} object that may be specified on the request.
+ * The {@link AccessCondition#generateIfMatchCondition(String)} and
+ * {@link AccessCondition#generateIfNoneMatchCondition(String)} methods take an ETag value and return an
+ * {@link AccessCondition} object that may be specified on the request.
*
* @return A
+ * If you are using {@link CloudAppendBlob} and are certain of a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag to
+ *
+ * If you are using {@link CloudAppendBlob} and are certain of a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag to
+ *
+ * If you are using {@link CloudAppendBlob} and are certain of a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag to
+ *
+ * If you are using {@link CloudAppendBlob} and are certain of a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag to
+ *
- * The {@link AccessCondition#ifMatch} and {@link AccessCondition#ifNoneMatch} methods take an ETag value and return
- * an {@link AccessCondition} object that may be specified on the request.
+ * The {@link AccessCondition#generateIfMatchCondition(String)} and
+ * {@link AccessCondition#generateIfNoneMatchCondition(String)} methods take an ETag value and return an
+ * {@link AccessCondition} object that may be specified on the request.
*
* @return A
+ * You can change the absorbConditionalErrorsOnRetry value on this request by setting this property. You can also
+ * change the value on the {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests
+ * made via the service client will use that absorbConditionalErrorsOnRetry value.
+ *
+ * @param absorbConditionalErrorsOnRetry
+ * the absorbConditionalErrorsOnRetry to set
+ */
+ public void setAbsorbConditionalErrorsOnRetry(final Boolean absorbConditionalErrorsOnRetry) {
+ this.absorbConditionalErrorsOnRetry = absorbConditionalErrorsOnRetry;
+ }
+
/**
* Sets the concurrent number of simultaneous requests per operation.
*
* The default concurrent request count is set in the client and is by default 1, indicating no concurrency. You can
* change the concurrent request count on this request by setting this property. You can also change the value on
- * the {@link BlobServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via the
+ * the {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests made via the
* service client will use that concurrent request count.
*
* @param concurrentRequestCount
@@ -253,7 +302,7 @@ public void setConcurrentRequestCount(final Integer concurrentRequestCount) {
*
* The default useTransactionalContentMD5 value is set in the client and is by default
* The default storeBlobContentMD5 value is set in the client and is by default
* The default disableContentMD5Validation value is set in the client and is by default
* The default threshold size is set in the client and is by default 32MB. You can change the threshold size on this
* request by setting this property. You can also change the value on the
- * {@link BlobServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via the service
+ * {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests made via the service
* client will use that threshold size.
*
* @param singleBlobPutThresholdInBytes
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java
index 1972af96f16ce..cb3b5514982e0 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobResponse.java
@@ -106,6 +106,13 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) {
properties.setPageBlobSequenceNumber(Long.parseLong(sequenceNumber));
}
+ // Get committed block count
+ final String comittedBlockCount = request.getHeaderField(Constants.HeaderConstants.BLOB_COMMITTED_BLOCK_COUNT);
+ if (!Utility.isNullOrEmpty(comittedBlockCount))
+ {
+ properties.setAppendBlobCommittedBlockCount(Integer.parseInt(comittedBlockCount));
+ }
+
attributes.setStorageUri(resourceURI);
attributes.setSnapshotID(snapshotID);
@@ -163,7 +170,8 @@ public static BlobContainerAttributes getBlobContainerAttributes(final HttpURLCo
public static CopyState getCopyState(final HttpURLConnection request) throws URISyntaxException, ParseException {
String copyStatusString = request.getHeaderField(Constants.HeaderConstants.COPY_STATUS);
if (!Utility.isNullOrEmpty(copyStatusString)) {
- CopyState copyState = new CopyState();
+ final CopyState copyState = new CopyState();
+
copyState.setStatus(CopyStatus.parse(copyStatusString));
copyState.setCopyId(request.getHeaderField(Constants.HeaderConstants.COPY_ID));
copyState.setStatusDescription(request.getHeaderField(Constants.HeaderConstants.COPY_STATUS_DESCRIPTION));
@@ -180,12 +188,12 @@ public static CopyState getCopyState(final HttpURLConnection request) throws URI
copyState.setSource(new URI(copySourceString));
}
- final String copyCompletionTimeString = request
- .getHeaderField(Constants.HeaderConstants.COPY_COMPLETION_TIME);
+ final String copyCompletionTimeString =
+ request.getHeaderField(Constants.HeaderConstants.COPY_COMPLETION_TIME);
if (!Utility.isNullOrEmpty(copyCompletionTimeString)) {
copyState.setCompletionTime(Utility.parseRFC1123DateFromStringInGMT(copyCompletionTimeString));
}
-
+
return copyState;
}
else {
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobType.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobType.java
index 254289efa5ecd..601b64c7229db 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobType.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobType.java
@@ -35,7 +35,12 @@ public enum BlobType {
/**
* Specifies the blob is a page blob.
*/
- PAGE_BLOB;
+ PAGE_BLOB,
+
+ /**
+ * Specifies the blob is an append blob.
+ */
+ APPEND_BLOB;
/**
* Returns the enum value representing the blob type for the specified string.
@@ -55,6 +60,9 @@ else if ("blockblob".equals(typeString.toLowerCase(Locale.US))) {
else if ("pageblob".equals(typeString.toLowerCase(Locale.US))) {
return PAGE_BLOB;
}
+ else if ("appendblob".equals(typeString.toLowerCase(Locale.US))) {
+ return APPEND_BLOB;
+ }
else {
return UNSPECIFIED;
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java
new file mode 100644
index 0000000000000..95d3726328765
--- /dev/null
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudAppendBlob.java
@@ -0,0 +1,995 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed 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 com.microsoft.azure.storage.blob;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.microsoft.azure.storage.AccessCondition;
+import com.microsoft.azure.storage.Constants;
+import com.microsoft.azure.storage.DoesServiceRequest;
+import com.microsoft.azure.storage.OperationContext;
+import com.microsoft.azure.storage.StorageCredentials;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.StorageUri;
+import com.microsoft.azure.storage.core.ExecutionEngine;
+import com.microsoft.azure.storage.core.SR;
+import com.microsoft.azure.storage.core.StorageRequest;
+import com.microsoft.azure.storage.core.StreamMd5AndLength;
+import com.microsoft.azure.storage.core.Utility;
+
+/**
+ * Represents a Microsoft Azure Append Blob.
+ */
+public final class CloudAppendBlob extends CloudBlob {
+ /**
+ * Creates an instance of the
+ * To avoid overwriting and instead throw an error, please use the
+ * {@link #createOrReplace(AccessCondition, BlobRequestOptions, OperationContext)} overload with the appropriate
+ * {@link AccessCondition}.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void createOrReplace() throws StorageException {
+ this.createOrReplace(null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Creates an append blob using the specified request options and operation context. If the blob already exists,
+ * this will replace it.
+ *
+ * To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
+ *
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ *
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * To avoid overwriting and instead throw an error, please use the
+ * {@link #openWriteNew(AccessCondition, BlobRequestOptions, OperationContext)} overload with the appropriate
+ * {@link AccessCondition}.
+ *
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
+ *
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you want to append data to an already existing blob, please see {@link #appendBlock(InputStream, long)}.
+ *
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
+ * If you want to append data to an already existing blob, please see {@link #appendBlock(InputStream, long)}.
+ *
+ * If you are doing writes in a single writer scenario, please look at
+ * {@link BlobRequestOptions#setAbsorbConditionalErrorsOnRetry(Boolean)} and see if setting this flag
+ * to
- * This format is used by both Shared Access and Copy blob operations.
+ * This format is used for Shared Access operations.
*
* @param ignoreSnapshotTime
*
- * Use {@link CloudBlobClient#setStreamMinimumReadSizeInBytes} to configure the read size.
+ * Use {@link #setStreamMinimumReadSizeInBytes(int)} to configure the read size.
*
* @return An
- * Use {@link CloudBlobClient#setStreamMinimumReadSizeInBytes} to configure the read size.
+ * Use {@link #setStreamMinimumReadSizeInBytes(int)} to configure the read size.
*
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the blob.
@@ -2369,70 +2496,54 @@ public final BlobInputStream openInputStream(final AccessCondition accessConditi
assertNoWriteOperationForSnapshot();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient,
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient,
false /* setStartTime */);
return new BlobInputStream(this, accessCondition, options, opContext);
}
-
+
/**
- * Parse Uri for SAS (Shared access signature) information.
- *
- * Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding
- * credentials instance. If existingClient is passed in, any SAS information found will not be supported. Otherwise
- * a new client is created based on SAS information or as anonymous credentials.
- *
+ * Verifies the passed in URI. Then parses it and uses its components to populate this resource's properties.
+ *
* @param completeUri
- * A {@link StorageUri} object which represents the complete Uri.
- * @param existingClient
- * A {@link CloudBlobClient} object which represents the client to use.
- * @param usePathStyleUris
- *
- * If a blob size is above the threshold, it will be uploaded as blocks.
- *
- * @deprecated use {@link #getDefaultRequestOptions().getSingleBlobPutThresholdInBytes()} instead.
- */
- @Deprecated
- public int getSingleBlobPutThresholdInBytes() {
- return this.getDefaultRequestOptions().getSingleBlobPutThresholdInBytes();
- }
-
/**
* Returns an enumerable collection of blob containers for this Blob service client.
*
@@ -336,7 +301,7 @@ private Iterable
+ * To avoid overwriting and instead throw an error, please use the
+ * {@link #openOutputStream(AccessCondition, BlobRequestOptions, OperationContext)} overload with the appropriate
+ * {@link AccessCondition}.
*
* @return A {@link BlobOutputStream} object used to write data to the blob.
*
@@ -449,7 +637,10 @@ public BlobOutputStream openOutputStream() throws StorageException {
/**
* Creates and opens an output stream to write data to the block blob using the specified request options and
- * operation context.
+ * operation context. If the blob already exists on the service, it will be overwritten.
+ *
+ * To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
*
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the blob.
@@ -467,7 +658,7 @@ public BlobOutputStream openOutputStream() throws StorageException {
* @throws StorageException
* If a storage service error occurred.
*/
- public BlobOutputStream openOutputStream(final AccessCondition accessCondition, BlobRequestOptions options,
+ public BlobOutputStream openOutputStream(AccessCondition accessCondition, BlobRequestOptions options,
OperationContext opContext) throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
@@ -475,14 +666,23 @@ public BlobOutputStream openOutputStream(final AccessCondition accessCondition,
assertNoWriteOperationForSnapshot();
- options = BlobRequestOptions.applyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient,
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient,
false /* setStartTime */);
+
+ // Apply any conditional access conditions up front
+ if (accessCondition != null &&
+ (accessCondition.getIfMatch() != null || accessCondition.getIfNoneMatch() != null
+ || accessCondition.getIfModifiedSinceDate() != null
+ || accessCondition.getIfUnmodifiedSinceDate() != null)) {
+ this.downloadAttributes(accessCondition, options, opContext);
+ }
return new BlobOutputStream(this, accessCondition, options, opContext);
}
/**
- * Uploads the source stream data to the block blob.
+ * Uploads the source stream data to the block blob. If the blob already exists on the service, it will be
+ * overwritten.
*
* @param sourceStream
* An {@link InputStream} object that represents the input stream to write to the block blob.
@@ -502,6 +702,7 @@ public void upload(final InputStream sourceStream, final long length) throws Sto
/**
* Uploads the source stream data to the blob, using the specified lease ID, request options, and operation context.
+ * If the blob already exists on the service, it will be overwritten.
*
* @param sourceStream
* An {@link InputStream} object that represents the input stream to write to the block blob.
@@ -538,7 +739,7 @@ public void upload(final InputStream sourceStream, final long length, final Acce
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient);
StreamMd5AndLength descriptor = new StreamMd5AndLength();
descriptor.setLength(length);
@@ -648,7 +849,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlob blob, OperationCo
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, length, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, length, context);
}
@Override
@@ -739,17 +940,13 @@ public void uploadBlock(final String blockId, final InputStream sourceStream, fi
throw new IllegalArgumentException(SR.STREAM_LENGTH_NEGATIVE);
}
- if (length > 4 * Constants.MB) {
- throw new IllegalArgumentException(SR.STREAM_LENGTH_GREATER_THAN_4MB);
- }
-
assertNoWriteOperationForSnapshot();
if (opContext == null) {
opContext = new OperationContext();
}
- options = BlobRequestOptions.applyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient);
// Assert block length
if (Utility.isNullOrEmpty(blockId) || !Base64.validateIsBase64String(blockId)) {
@@ -776,7 +973,6 @@ public void uploadBlock(final String blockId, final InputStream sourceStream, fi
else if (length < 0 || options.getUseTransactionalContentMD5()) {
// If the stream is of unknown length or we need to calculate the
// MD5, then we we need to read the stream contents first
-
descriptor = Utility.analyzeStream(sourceStream, length, -1L, true /* rewindSourceStream */,
options.getUseTransactionalContentMD5());
}
@@ -844,7 +1040,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlob blob, OperationCo
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, length, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, length, context);
}
@Override
@@ -869,7 +1065,8 @@ public void recoveryAction(OperationContext context) throws IOException {
}
/**
- * Uploads a blob from a string using the platform's default encoding.
+ * Uploads a blob from a string using the platform's default encoding. If the blob already exists on the service, it
+ * will be overwritten.
*
* @param content
* A
+ * To avoid overwriting and instead throw an error, please use the
+ * {@link #openWriteNew(long, AccessCondition, BlobRequestOptions, OperationContext)} overload with the appropriate
+ * {@link AccessCondition}.
*
* @param length
* A
+ * To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
*
* @param length
* A
@@ -264,7 +626,7 @@ public void clearRange(final long offset, final long length, final AccessConditi
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
final FileRange range = new FileRange(offset, offset + length - 1);
@@ -273,7 +635,7 @@ public void clearRange(final long offset, final long length, final AccessConditi
}
/**
- * Creates a file.
+ * Creates a file. If the file already exists, this will replace it.
*
* @param size
* A
- * This method populates the file's system properties and user-defined metadata. Before reading or modifying a
- * file's properties or metadata, call this method or its overload to retrieve the latest values for the file's
- * properties and metadata from the Microsoft Azure storage service.
+ * This method populates the file's system properties and user-defined metadata. Before reading or modifying
+ * a file's properties or metadata, call this method or its overload to retrieve the latest values for
+ * the file's properties and metadata from the Microsoft Azure storage service.
*
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the file.
@@ -1331,7 +1696,7 @@ public final void downloadAttributes(final AccessCondition accessCondition, File
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
this.downloadAttributesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -1339,8 +1704,8 @@ public final void downloadAttributes(final AccessCondition accessCondition, File
private StorageRequest
+ * This format is used for Shared Access operations.
+ *
+ * @return The canonical name in the format of /<service-name>/<account-name>
+ * /<share-name>/<file-name>.
+ */
+ String getCanonicalName() {
+ StringBuilder canonicalName = new StringBuilder("/");
+ canonicalName.append(SR.FILE);
+
+ String rawPath = this.getUri().getRawPath();
+ if (this.fileServiceClient.isUsePathStyleUris()) {
+ canonicalName.append(rawPath);
+ }
+ else {
+ canonicalName.append(PathUtility.getCanonicalPathFromCredentials(
+ this.getServiceClient().getCredentials(), rawPath));
+ }
+
+ return canonicalName.toString();
+ }
+
+ /**
+ * Returns the Azure File's copy state.
+ *
+ * @return A {@link CopyState} object that represents the copy state of the file.
+ */
+ public CopyState getCopyState() {
+ return this.properties.getCopyState();
+ }
+
/**
* Opens a file input stream to download the file.
*
- * Use {@link CloudFileClient#setStreamMinimumReadSizeInBytes} to configure the read size.
+ * Use {@link CloudFile#setStreamMinimumReadSizeInBytes(int)} to configure the read size.
*
* @return An
- * Use {@link CloudFileClient#setStreamMinimumReadSizeInBytes} to configure the read size.
+ * Use {@link CloudFile#setStreamMinimumReadSizeInBytes(int)} to configure the read size.
*
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the file.
@@ -1514,7 +1974,7 @@ public final FileInputStream openRead() throws StorageException {
* is used to track requests to the storage service, and to provide additional runtime information about
* the operation.
*
- * @return An
+ * To avoid overwriting and instead throw an error, please use the
+ * {@link #openWriteNew(long, AccessCondition, FileRequestOptions, OperationContext)} overload with the appropriate
+ * {@link AccessCondition}.
*
* @param length
* A
+ * To avoid overwriting and instead throw an error, please pass in an {@link AccessCondition} generated using
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
*
* @param length
* A
- * Directories, which are encapsulated as {@link CloudFileDirectories} objects, hold files and can also contain
+ * Directories, which are encapsulated as {@link CloudFileDirectory} objects, hold files and can also contain
* sub-directories.
*/
public final class CloudFileDirectory implements ListFileItem {
-
/**
* Holds the share reference.
*/
@@ -74,12 +77,69 @@ public final class CloudFileDirectory implements ListFileItem {
* Holds the name of the directory.
*/
private String name;
+
+ /**
+ * Represents the directory metadata.
+ */
+ private HashMapString
that represents the name of the access key to be used when signing the request.
*/
- protected void setKeyName(final String keyName) {
- this.keyName = keyName;
+ protected void setKey(final StorageKey key) {
+ this.key = key;
}
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/OperationContext.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/OperationContext.java
index 5af70e64fc11d..d35b8cba349d0 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/OperationContext.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/OperationContext.java
@@ -237,7 +237,7 @@ public ArrayListtrue
if logging is enabled by default; otherwise false
.
@@ -496,10 +496,11 @@ public static boolean isLoggingEnabledByDefault() {
/**
* Specifies whether the client library should produce log entries by default. The default can be overridden
- * to turn on logging for an individual operation context instance by using {@link setLoggingEnabled}.
+ * to turn on logging for an individual operation context instance by using {@link #setLoggingEnabled}.
*
* @param enableLoggingByDefault
- * true
if logging should be enabled by default; otherwise false
if logging should be disabled by default.
+ * true
if logging should be enabled by default; otherwise false
if logging should
+ * be disabled by default.
*/
public static void setLoggingEnabledByDefault(boolean enableLoggingByDefault) {
OperationContext.enableLoggingByDefault = enableLoggingByDefault;
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/RequestOptions.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/RequestOptions.java
index 9abd95805cfc7..2b458e51aca4a 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/RequestOptions.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/RequestOptions.java
@@ -78,10 +78,10 @@ public RequestOptions(final RequestOptions other) {
/**
* Populates the default timeout, retry policy, and location mode from client if they are null.
*
- * @param options
+ * @param modifiedOptions
* The input options to copy from when applying defaults
*/
- protected static final RequestOptions applyBaseDefaultsInternal(final RequestOptions modifiedOptions) {
+ protected static void applyBaseDefaultsInternal(final RequestOptions modifiedOptions) {
Utility.assertNotNull("modifiedOptions", modifiedOptions);
if (modifiedOptions.getRetryPolicyFactory() == null) {
modifiedOptions.setRetryPolicyFactory(new RetryExponentialRetry());
@@ -90,14 +90,12 @@ protected static final RequestOptions applyBaseDefaultsInternal(final RequestOpt
if (modifiedOptions.getLocationMode() == null) {
modifiedOptions.setLocationMode(LocationMode.PRIMARY_ONLY);
}
-
- return modifiedOptions;
}
/**
* Populates any null fields in the first requestOptions object with values from the second requestOptions object.
*/
- protected static final RequestOptions populateRequestOptions(RequestOptions modifiedOptions,
+ protected static void populateRequestOptions(RequestOptions modifiedOptions,
final RequestOptions clientOptions, final boolean setStartTime) {
if (modifiedOptions.getRetryPolicyFactory() == null) {
modifiedOptions.setRetryPolicyFactory(clientOptions.getRetryPolicyFactory());
@@ -120,8 +118,6 @@ protected static final RequestOptions populateRequestOptions(RequestOptions modi
modifiedOptions.setOperationExpiryTimeInMs(new Date().getTime()
+ modifiedOptions.getMaximumExecutionTimeInMs());
}
-
- return modifiedOptions;
}
/**
@@ -214,7 +210,7 @@ public final void setRetryPolicyFactory(final RetryPolicyFactory retryPolicyFact
* {@link ServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via the service
* client will use that server timeout.
*
- * @param timeoutInMs
+ * @param timeoutIntervalInMs
* The timeout, in milliseconds, to use for this request.
*/
public final void setTimeoutIntervalInMs(final Integer timeoutIntervalInMs) {
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryExponentialRetry.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryExponentialRetry.java
index d32bf370df4ed..82065d1a8490a 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryExponentialRetry.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryExponentialRetry.java
@@ -115,10 +115,11 @@ public RetryInfo evaluate(RetryContext retryContext, OperationContext operationC
boolean secondaryNotFound = this.evaluateLastAttemptAndSecondaryNotFound(retryContext);
if (retryContext.getCurrentRetryCount() < this.maximumAttempts) {
- if ((!secondaryNotFound && retryContext.getLastRequestResult().getStatusCode() >= 400 && retryContext
- .getLastRequestResult().getStatusCode() < 500)
- || retryContext.getLastRequestResult().getStatusCode() == HttpURLConnection.HTTP_NOT_IMPLEMENTED
- || retryContext.getLastRequestResult().getStatusCode() == HttpURLConnection.HTTP_VERSION) {
+ int statusCode = retryContext.getLastRequestResult().getStatusCode();
+ if ((!secondaryNotFound && statusCode >= 400 && statusCode < 500)
+ || statusCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED
+ || statusCode == HttpURLConnection.HTTP_VERSION
+ || statusCode == Constants.HeaderConstants.HTTP_UNUSED_306) {
return null;
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryLinearRetry.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryLinearRetry.java
index 3c32552306452..474666db698eb 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryLinearRetry.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryLinearRetry.java
@@ -77,10 +77,11 @@ public RetryInfo evaluate(RetryContext retryContext, OperationContext operationC
boolean secondaryNotFound = this.evaluateLastAttemptAndSecondaryNotFound(retryContext);
if (retryContext.getCurrentRetryCount() < this.maximumAttempts) {
- if ((!secondaryNotFound && retryContext.getLastRequestResult().getStatusCode() >= 400 && retryContext
- .getLastRequestResult().getStatusCode() < 500)
- || retryContext.getLastRequestResult().getStatusCode() == HttpURLConnection.HTTP_NOT_IMPLEMENTED
- || retryContext.getLastRequestResult().getStatusCode() == HttpURLConnection.HTTP_VERSION) {
+ int statusCode = retryContext.getLastRequestResult().getStatusCode();
+ if ((!secondaryNotFound && statusCode >= 400 && statusCode < 500)
+ || statusCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED
+ || statusCode == HttpURLConnection.HTTP_VERSION
+ || statusCode == Constants.HeaderConstants.HTTP_UNUSED_306) {
return null;
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryingEvent.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryingEvent.java
index 2e16b749a91c5..47f4299a274c8 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryingEvent.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/RetryingEvent.java
@@ -37,8 +37,9 @@ public final class RetryingEvent extends BaseEvent {
* a connection object.
* @param requestResult
* A {@link RequestResult} object that represents the current request result.
- * @param retryCount
- * The number of retries done for this request (including the pending retry).
+ * @param retryContext
+ * A {@link RetryContext} object which contains the number of retries done for this request (including
+ * the pending retry) and other retry information.
*/
public RetryingEvent(OperationContext opContext, Object connectionObject, RequestResult requestResult,
RetryContext retryContext) {
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceClient.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceClient.java
index a4c6c999b80d3..f5338be3f41fc 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceClient.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceClient.java
@@ -48,12 +48,6 @@ public abstract class ServiceClient {
*/
private boolean usePathStyleUris;
- /**
- * Holds the AuthenticationScheme associated with this Service Client.
- */
- @SuppressWarnings("deprecation")
- protected AuthenticationScheme authenticationScheme = AuthenticationScheme.SHAREDKEYFULL;
-
/**
* Creates an instance of the ServiceClient
class using the specified service endpoint and account
* credentials.
@@ -89,10 +83,10 @@ public HttpURLConnection buildRequest(ServiceClient client, Void parentObject, O
public void signRequest(HttpURLConnection connection, ServiceClient client, OperationContext context)
throws Exception {
if (signAsTable) {
- StorageRequest.signTableRequest(connection, client, -1, null);
+ StorageRequest.signTableRequest(connection, client, -1, context);
}
else {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1, context);
}
}
@@ -138,10 +132,10 @@ public HttpURLConnection buildRequest(ServiceClient client, Void parentObject, O
public void signRequest(HttpURLConnection connection, ServiceClient client, OperationContext context)
throws Exception {
if (signAsTable) {
- StorageRequest.signTableRequest(connection, client, -1, null);
+ StorageRequest.signTableRequest(connection, client, -1, context);
}
else {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1, context);
}
}
@@ -175,18 +169,6 @@ public final StorageCredentials getCredentials() {
return this.credentials;
}
- /**
- * Returns the AuthenticationScheme associated with this service client.
- *
- * @return An {@link AuthenticationScheme} object which represents the authentication scheme associated with this
- * client.
- *
- * @deprecated as of 2.0.0. In the future only SharedKeyFull will be used.
- */
- public final AuthenticationScheme getAuthenticationScheme() {
- return this.authenticationScheme;
- }
-
/**
* Returns the base URI for this service client.
*
@@ -234,19 +216,6 @@ protected final void setStorageUri(final StorageUri storageUri) {
this.storageUri = storageUri;
}
- /**
- * Sets the Authentication Scheme to use with this service client.
- *
- * @param scheme
- * An {@link AuthenticationScheme} object which represents the authentication scheme being assigned for
- * the service client.
- *
- * @deprecated as of 2.0.0. In the future, only SharedKeyFull will be used.
- */
- public final void setAuthenticationScheme(final AuthenticationScheme scheme) {
- this.authenticationScheme = scheme;
- }
-
protected StorageRequestServiceClient
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceProperties.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceProperties.java
index 84cd8c80b6f9d..3c8d3d26c7e1b 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceProperties.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/ServiceProperties.java
@@ -124,7 +124,7 @@ public CorsProperties getCors() {
/**
* Sets the Cross-Origin Resource Sharing (CORS) properties.
*
- * @param CORS
+ * @param cors
* A {@link CorsProperties} object which represents the CORS properties.
*/
public void setCors(final CorsProperties cors) {
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessHeaders.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessHeaders.java
new file mode 100644
index 0000000000000..47c674a4fd90c
--- /dev/null
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessHeaders.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed 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 com.microsoft.azure.storage;
+
+import com.microsoft.azure.storage.core.Utility;
+
+/**
+ * RESERVED FOR INTERNAL USE. Represents the optional headers that can be returned using SAS.
+ */
+public abstract class SharedAccessHeaders {
+ /**
+ * The cache-control header returned.
+ */
+ private String cacheControl;
+
+ /**
+ * The content-disposition header returned.
+ */
+ private String contentDisposition;
+
+ /**
+ * The content-encoding header returned.
+ */
+ private String contentEncoding;
+
+ /**
+ * The content-language header returned.
+ */
+ private String contentLanguage;
+
+ /**
+ * The content-type header returned.
+ */
+ private String contentType;
+
+ /**
+ * Initializes a new instance of the {@link SharedAccessHeaders} class.
+ */
+ public SharedAccessHeaders() {
+ }
+
+ /**
+ * Initializes a new instance of the {@link SharedAccessHeaders} class based on an existing instance.
+ *
+ * @param other
+ * A {@link SharedAccessHeaders} object which specifies the set of properties to clone.
+ */
+ public SharedAccessHeaders(SharedAccessHeaders other) {
+ Utility.assertNotNull("other", other);
+
+ this.contentType = other.contentType;
+ this.contentDisposition = other.contentDisposition;
+ this.contentEncoding = other.contentEncoding;
+ this.contentLanguage = other.contentLanguage;
+ this.cacheControl = other.cacheControl;
+ }
+
+ /**
+ * Gets the cache control header.
+ *
+ * @return A String
which represents the cache control header.
+ */
+ public String getCacheControl() {
+ return this.cacheControl;
+ }
+
+ /**
+ * Sets the cache control header.
+ *
+ * @param cacheControl
+ * A String
which specifies the cache control header.
+ */
+ public void setCacheControl(String cacheControl) {
+ this.cacheControl = cacheControl;
+ }
+
+ /**
+ * Gets the content disposition header.
+ *
+ * @return A String
which represents the content disposition header.
+ */
+ public String getContentDisposition() {
+ return this.contentDisposition;
+ }
+
+ /**
+ * Sets the content disposition header.
+ *
+ * @param contentDisposition
+ * A String
which specifies the content disposition header.
+ */
+ public void setContentDisposition(String contentDisposition) {
+ this.contentDisposition = contentDisposition;
+ }
+
+ /**
+ * Gets the content encoding header.
+ *
+ * @return A String
which represents the content encoding header.
+ */
+ public String getContentEncoding() {
+ return this.contentEncoding;
+ }
+
+ /**
+ * Sets the content encoding header.
+ *
+ * @param contentEncoding
+ * A String
which specifies the content encoding header.
+ */
+ public void setContentEncoding(String contentEncoding) {
+ this.contentEncoding = contentEncoding;
+ }
+
+ /**
+ * Gets the content language header.
+ *
+ * @return A String
which represents the content language header.
+ */
+ public String getContentLanguage() {
+ return this.contentLanguage;
+ }
+
+ /**
+ * Sets the content language header.
+ *
+ * @param contentLanguage
+ * A String
which specifies the content language header.
+ */
+ public void setContentLanguage(String contentLanguage) {
+ this.contentLanguage = contentLanguage;
+ }
+
+ /**
+ * Gets the content type header.
+ *
+ * @return A String
which represents the content type header.
+ */
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ /**
+ * Sets the content type header.
+ *
+ * @param contentType
+ * A String
which specifies the content type header.
+ */
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageCredentialsAccountAndKey.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageCredentialsAccountAndKey.java
index 13a23191d2220..85c4ab8d8bcae 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageCredentialsAccountAndKey.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageCredentialsAccountAndKey.java
@@ -17,6 +17,8 @@
import java.net.URI;
import com.microsoft.azure.storage.core.Base64;
+import com.microsoft.azure.storage.core.SR;
+import com.microsoft.azure.storage.core.Utility;
/**
* Represents storage account credentials, based on storage account and access key, for accessing the Microsoft Azure
@@ -27,6 +29,7 @@ public final class StorageCredentialsAccountAndKey extends StorageCredentials {
/**
* The internal Credentials associated with the StorageCredentials.
*/
+ @SuppressWarnings("deprecation")
private Credentials credentials;
/**
@@ -38,6 +41,7 @@ public final class StorageCredentialsAccountAndKey extends StorageCredentials {
* @param key
* An array of bytes that represent the account access key.
*/
+ @SuppressWarnings("deprecation")
public StorageCredentialsAccountAndKey(final String accountName, final byte[] key) {
this.credentials = new Credentials(accountName, key);
}
@@ -51,23 +55,88 @@ public StorageCredentialsAccountAndKey(final String accountName, final byte[] ke
* @param key
* A String
that represents the Base-64-encoded account access key.
*/
+ @SuppressWarnings("deprecation")
public StorageCredentialsAccountAndKey(final String accountName, final String key) {
- this(accountName, Base64.decode(key));
+ this.credentials = new Credentials(accountName, key);
}
/**
- * Returns the associated account name for the credentials.
+ * Gets the account name.
*
- * @return A String
that contains the account name for the credentials.
+ * @return A String
that contains the account name.
*/
+ @SuppressWarnings("deprecation")
@Override
public String getAccountName() {
return this.credentials.getAccountName();
}
+
+ /**
+ * Exports the value of the access key to a Base64-encoded string.
+ *
+ * @return A String
that represents the Base64-encoded access key.
+ */
+ @SuppressWarnings("deprecation")
+ public String exportBase64EncodedKey() {
+ return this.credentials.getKey().getBase64EncodedKey();
+ }
+
+ /**
+ * Exports the value of the access key to an array of bytes.
+ *
+ * @return A byte array that represents the access key.
+ */
+ @SuppressWarnings("deprecation")
+ public byte[] exportKey() {
+ return this.credentials.getKey().getKey();
+ }
+
+ /**
+ * Sets the account name.
+ *
+ * @param accountName
+ * A String
that contains the account name.
+ */
+ @SuppressWarnings("deprecation")
+ public void setAccountName(String accountName) {
+ this.credentials.setAccountName(accountName);
+ }
+
+ /**
+ * Sets the name of the access key to be used when signing the request.
+ *
+ * @param key
+ * A String
that represents the name of the access key to be used when signing the request.
+ */
+ @SuppressWarnings("deprecation")
+ public void updateKey(final String key) {
+ if (Utility.isNullOrEmptyOrWhitespace(key) || Base64.validateIsBase64String(key)) {
+ throw new IllegalArgumentException(SR.INVALID_KEY);
+ }
+
+ this.credentials.setKey(new StorageKey(Base64.decode(key)));
+ }
+
+ /**
+ * Sets the name of the access key to be used when signing the request.
+ *
+ * @param key
+ * A String
that represents the name of the access key to be used when signing the request.
+ */
+ @SuppressWarnings("deprecation")
+ public void updateKey(final byte[] key) {
+ if (key == null || key.length == 0) {
+ throw new IllegalArgumentException(SR.INVALID_KEY);
+ }
+
+ this.credentials.setKey(new StorageKey(key));
+ }
/**
* Gets the name of the key used by these credentials.
+ * @deprecated as of 3.0.0. The key name property is only useful internally.
*/
+ @Deprecated
public String getAccountKeyName() {
return this.credentials.getKeyName();
}
@@ -77,7 +146,10 @@ public String getAccountKeyName() {
*
* @return A Credentials
object that contains the internal credentials associated with this instance of
* the StorageCredentialsAccountAndKey
class.
+ * @deprecated as of 3.0.0. Please use {@link #getAccountName()}, {@link #exportKey()}, or
+ * {@link #exportBase64EncodedKey()}
*/
+ @Deprecated
public Credentials getCredentials() {
return this.credentials;
}
@@ -88,7 +160,10 @@ public Credentials getCredentials() {
* @param credentials
* A Credentials
object that represents the credentials to set for this instance of the
* StorageCredentialsAccountAndKey
class.
+ * @deprecated as of 3.0.0. Please use {@link #setAccountName(String)}, {@link #updateKey(String)}, or
+ * {@link #updateKey(byte[])}
*/
+ @Deprecated
public void setCredentials(final Credentials credentials) {
this.credentials = credentials;
}
@@ -101,6 +176,7 @@ public void setCredentials(final Credentials credentials) {
*
* @return A String
that represents this object, optionally including sensitive data.
*/
+ @SuppressWarnings("deprecation")
@Override
public String toString(final boolean exportSecrets) {
return String.format("%s=%s;%s=%s", CloudStorageAccount.ACCOUNT_NAME_NAME, this.getAccountName(),
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageErrorCodeStrings.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageErrorCodeStrings.java
index 98e72e6e0e38d..214ec545a45fd 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageErrorCodeStrings.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageErrorCodeStrings.java
@@ -174,6 +174,11 @@ public final class StorageErrorCodeStrings {
*/
public static final String INVALID_AUTHENTICATION_INFO = "InvalidAuthenticationInfo";
+ /**
+ * Error code that may be returned when the specified append offset is invalid.
+ */
+ public static final String INVALID_APPEND_POSITION = "AppendPositionConditionNotMet";
+
/**
* An incorrect blob type was specified.
*/
@@ -214,6 +219,11 @@ public final class StorageErrorCodeStrings {
*/
public static final String INVALID_MARKER = "InvalidMarker";
+ /**
+ * Error code that may be returned when the specified max blob size is exceeded.
+ */
+ public static final String INVALID_MAX_BLOB_SIZE_CONDITION = "MaxBlobSizeConditionNotMet";
+
/**
* The specified MD5 hash is invalid.
*/
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageEventMultiCaster.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageEventMultiCaster.java
index 890d2ff010016..a66df16993e2f 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageEventMultiCaster.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageEventMultiCaster.java
@@ -21,7 +21,7 @@
*
* @param String
that represents the status description.
- * @param details
- * A {@link StorageExtendedErrorInformation} object that represents the error details returned by the
- * operation.
* @param inner
* An Exception
object that represents a reference to the initial exception, if one exists.
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageKey.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageKey.java
index 4aa950c0e6e2f..7188a819467c9 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageKey.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/StorageKey.java
@@ -26,7 +26,9 @@
/**
* Represents a container for a storage key.
+ * @deprecated as of 3.0.0. Please use the methods on {@link StorageCredentialsAccountAndKey}.
*/
+@Deprecated
public final class StorageKey {
/**
* Computes a signature for the specified string using the HMAC-SHA256 algorithm.
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClient.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClient.java
index df92a0bb91dfe..32d9690355b41 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClient.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/analytics/CloudAnalyticsClient.java
@@ -361,7 +361,7 @@ public IterableString
which represents the ETag.
*/
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java
index 7917d6b9c932d..c1ada37373c71 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobListHandler.java
@@ -117,6 +117,9 @@ public void endElement(String uri, String localName, String qName) throws SAXExc
else if (this.properties.getBlobType() == BlobType.PAGE_BLOB) {
retBlob = this.container.getPageBlobReference(this.blobName);
}
+ else if (this.properties.getBlobType() == BlobType.APPEND_BLOB) {
+ retBlob = this.container.getAppendBlobReference(this.blobName);
+ }
else {
throw new SAXException(SR.INVALID_RESPONSE_RECEIVED);
}
@@ -229,12 +232,15 @@ else if (Constants.HeaderConstants.CONTENT_DISPOSITION.equals(currentNode)) {
}
else if (BlobConstants.BLOB_TYPE_ELEMENT.equals(currentNode)) {
final String tempString = value;
- if (tempString.equals(BlobConstants.BLOCK_BLOB_VALUE)) {
+ if (tempString.equals(BlobConstants.BLOCK_BLOB)) {
this.properties.setBlobType(BlobType.BLOCK_BLOB);
}
- else if (tempString.equals(BlobConstants.PAGE_BLOB_VALUE.toString())) {
+ else if (tempString.equals(BlobConstants.PAGE_BLOB.toString())) {
this.properties.setBlobType(BlobType.PAGE_BLOB);
}
+ else if (tempString.equals(BlobConstants.APPEND_BLOB.toString())) {
+ this.properties.setBlobType(BlobType.APPEND_BLOB);
+ }
else {
throw new SAXException(SR.INVALID_RESPONSE_RECEIVED);
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobOutputStream.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobOutputStream.java
index 7d732333d941f..f7b31c8a99f98 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobOutputStream.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobOutputStream.java
@@ -19,23 +19,31 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Random;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorCompletionService;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import com.microsoft.azure.storage.AccessCondition;
import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.DoesServiceRequest;
import com.microsoft.azure.storage.OperationContext;
+import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.core.Base64;
+import com.microsoft.azure.storage.core.Logger;
import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.core.Utility;
@@ -43,45 +51,43 @@
* The class is an append-only stream for writing into storage.
*/
public final class BlobOutputStream extends OutputStream {
- /**
- * Holds the random number generator used to create starting blockIDs.
- */
- private static Random blockSequenceGenerator = new Random();
/**
- * Holds the reference to the blob this stream is associated with.
+ * Holds the {@link AccessCondition} object that represents the access conditions for the blob.
*/
- private final CloudBlob parentBlobRef;
+ private AccessCondition accessCondition;
/**
- * Determines if this stream is used against a page blob or block blob.
+ * Used for block blobs, holds the block id prefix.
*/
- private BlobType streamType = BlobType.UNSPECIFIED;
+ private String blockIdPrefix;
/**
- * A flag to determine if the stream is faulted, if so the lasterror will be thrown on next operation.
+ * Used for block blobs, holds the block list.
*/
- volatile boolean streamFaulted;
+ private ArrayListlong
which represents the length of the page blob in bytes, which must be a multiple of
* 512.
@@ -233,8 +228,44 @@ protected BlobOutputStream(final CloudPageBlob parentBlob, final long length,
throws StorageException {
this(parentBlob, accessCondition, options, opContext);
this.streamType = BlobType.PAGE_BLOB;
+
this.internalWriteThreshold = (int) Math.min(this.parentBlobRef.getStreamWriteSizeInBytes(), length);
}
+
+ /**
+ * Initializes a new instance of the BlobOutputStream class for a CloudAppendBlob
+ *
+ * @param parentBlob
+ * A {@link CloudAppendBlob} object which represents the blob that this stream is associated with.
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object which specifies any additional options for the request
+ * @param opContext
+ * An {@link OperationContext} object which is used to track the execution of the operation
+ *
+ * @throws StorageException
+ * An exception representing any error which occurred during the operation.
+ */
+ @DoesServiceRequest
+ protected BlobOutputStream(final CloudAppendBlob parentBlob, final AccessCondition accessCondition,
+ final BlobRequestOptions options, final OperationContext opContext)
+ throws StorageException {
+ this((CloudBlob)parentBlob, accessCondition, options, opContext);
+ this.streamType = BlobType.APPEND_BLOB;
+
+ this.accessCondition = accessCondition != null ? accessCondition : new AccessCondition();
+ if (this.accessCondition.getIfAppendPositionEqual() != null) {
+ this.currentBlobOffset = this.accessCondition.getIfAppendPositionEqual();
+ }
+ else {
+ // If this is an existing blob, we've done a downloadProperties to get the length
+ // If this is a new blob, getLength will correctly return 0
+ this.currentBlobOffset = parentBlob.getProperties().getLength();
+ }
+
+ this.internalWriteThreshold = this.parentBlobRef.getStreamWriteSizeInBytes();
+ }
/**
* Helper function to check if the stream is faulted, if it is it surfaces the exception.
@@ -244,10 +275,8 @@ protected BlobOutputStream(final CloudPageBlob parentBlob, final long length,
* closed.
*/
private void checkStreamState() throws IOException {
- synchronized (this.lastErrorLock) {
- if (this.streamFaulted) {
- throw this.lastError;
- }
+ if (this.lastError != null) {
+ throw this.lastError;
}
}
@@ -260,7 +289,7 @@ private void checkStreamState() throws IOException {
*/
@Override
@DoesServiceRequest
- public void close() throws IOException {
+ public synchronized void close() throws IOException {
try {
// if the user has already closed the stream, this will throw a STREAM_CLOSED exception
// if an exception was thrown by any thread in the threadExecutor, realize it now
@@ -282,10 +311,7 @@ public void close() throws IOException {
}
finally {
// if close() is called again, an exception will be thrown
- synchronized (this.lastErrorLock) {
- this.streamFaulted = true;
- this.lastError = new IOException(SR.STREAM_CLOSED);
- }
+ this.lastError = new IOException(SR.STREAM_CLOSED);
// if an exception was thrown and the executor was not yet closed, call shutDownNow() to cancel all tasks
// and shutdown the ExecutorService
@@ -302,7 +328,7 @@ public void close() throws IOException {
* An exception representing any error which occurred during the operation.
*/
@DoesServiceRequest
- private void commit() throws StorageException {
+ private synchronized void commit() throws StorageException {
if (this.options.getStoreBlobContentMD5()) {
this.parentBlobRef.getProperties().setContentMD5(Base64.encode(this.md5Digest.digest()));
}
@@ -312,11 +338,11 @@ private void commit() throws StorageException {
final CloudBlockBlob blobRef = (CloudBlockBlob) this.parentBlobRef;
blobRef.commitBlockList(this.blockList, this.accessCondition, this.options, this.opContext);
}
- else if (this.streamType == BlobType.PAGE_BLOB) {
+ else if (this.options.getStoreBlobContentMD5()) {
this.parentBlobRef.uploadProperties(this.accessCondition, this.options, this.opContext);
}
}
-
+
/**
* Dispatches a write operation for a given length.
*
@@ -329,86 +355,140 @@ else if (this.streamType == BlobType.PAGE_BLOB) {
* closed.
*/
@DoesServiceRequest
- private synchronized void dispatchWrite(final int writeLength) throws IOException {
+ private synchronized void dispatchWrite() throws IOException {
+ final int writeLength = this.outBuffer.size();
if (writeLength == 0) {
return;
}
+
+ if (this.streamType == BlobType.PAGE_BLOB && (writeLength % Constants.PAGE_SIZE != 0)) {
+ throw new IOException(String.format(SR.INVALID_NUMBER_OF_BYTES_IN_THE_BUFFER, writeLength));
+ }
Callableb.length
bytes from the specified byte array to this output stream.
+ * true
is acceptable for you.
*
* @param data
* A byte
array which represents the data to write.
@@ -486,6 +598,10 @@ public void write(final byte[] data) throws IOException {
/**
* Writes length bytes from the specified byte array starting at offset to this output stream.
+ * true
is acceptable for you.
*
* @param data
* A byte
array which represents the data to write.
@@ -510,6 +626,10 @@ public void write(final byte[] data, final int offset, final int length) throws
/**
* Writes all data from the InputStream to the Blob.
+ * true
is acceptable for you.
*
* @param sourceStream
* An {@link InputStream} object which species the data to write to the Blob.
@@ -529,6 +649,10 @@ public void write(final InputStream sourceStream, final long writeLength) throws
* Writes the specified byte to this output stream. The general contract for write is that one byte is written to
* the output stream. The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits
* of b are ignored.
+ * true
is acceptable for you.
*
* @param byteVal
* An int
which represents the bye value to write.
@@ -542,7 +666,7 @@ public void write(final InputStream sourceStream, final long writeLength) throws
public void write(final int byteVal) throws IOException {
this.write(new byte[] { (byte) (byteVal & 0xFF) });
}
-
+
/**
* Writes the data to the buffer and triggers writes to the service as needed.
*
@@ -562,8 +686,8 @@ public void write(final int byteVal) throws IOException {
private synchronized void writeInternal(final byte[] data, int offset, int length) throws IOException {
while (length > 0) {
this.checkStreamState();
-
- final int availableBufferBytes = this.internalWriteThreshold - this.currentBufferedBytes;
+
+ final int availableBufferBytes = this.internalWriteThreshold - this.outBuffer.size();
final int nextWrite = Math.min(availableBufferBytes, length);
// If we need to set MD5 then update the digest accordingly
@@ -572,12 +696,11 @@ private synchronized void writeInternal(final byte[] data, int offset, int lengt
}
this.outBuffer.write(data, offset, nextWrite);
- this.currentBufferedBytes += nextWrite;
offset += nextWrite;
length -= nextWrite;
- if (this.currentBufferedBytes == this.internalWriteThreshold) {
- this.dispatchWrite(this.internalWriteThreshold);
+ if (this.outBuffer.size() == this.internalWriteThreshold) {
+ this.dispatchWrite();
}
}
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java
index a80e561b3a6a3..c6c12da8fd73f 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobProperties.java
@@ -23,6 +23,11 @@
*/
public final class BlobProperties {
+ /**
+ * Represents the number of committed blocks on the append blob.
+ */
+ private Integer appendBlobCommittedBlockCount;
+
/**
* Represents the type of the blob.
*/
@@ -132,6 +137,7 @@ public BlobProperties(final BlobProperties other) {
this.contentMD5 = other.contentMD5;
this.cacheControl = other.cacheControl;
this.pageBlobSequenceNumber = other.pageBlobSequenceNumber;
+ this.appendBlobCommittedBlockCount = other.appendBlobCommittedBlockCount;
}
/**
@@ -144,6 +150,15 @@ public BlobProperties(final BlobType type) {
this.blobType = type;
}
+ /**
+ * If the blob is an append blob, gets the number of committed blocks.
+ *
+ * @return A Integer
value that represents the number of committed blocks.
+ */
+ public Integer getAppendBlobCommittedBlockCount() {
+ return this.appendBlobCommittedBlockCount;
+ }
+
/**
* Gets the blob type for the blob.
*
@@ -225,8 +240,9 @@ public CopyState getCopyState() {
* The ETag value is a unique identifier that is updated when a write operation is performed against the container.
* It may be used to perform operations conditionally, providing concurrency control and improved efficiency.
* String
which represents the ETag value.
*/
@@ -278,7 +294,7 @@ public LeaseDuration getLeaseDuration() {
public long getLength() {
return this.length;
}
-
+
/**
* If the blob is a page blob, gets the page blob's current sequence number.
*
@@ -348,6 +364,16 @@ public void setContentType(final String contentType) {
this.contentType = contentType;
}
+ /**
+ * If the blob is an append blob, sets the number of committed blocks.
+ *
+ * @param appendBlobCommittedBlockCount
+ * A Integer
value that represents the number of committed blocks.
+ */
+ protected void setAppendBlobCommittedBlockCount(final Integer appendBlobCommittedBlockCount) {
+ this.appendBlobCommittedBlockCount = appendBlobCommittedBlockCount;
+ }
+
/**
* Sets the blob type.
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java
index 6adeb924b6502..7ead9e0aff441 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequest.java
@@ -36,6 +36,8 @@
*/
final class BlobRequest {
+ private static final String APPEND_BLOCK_QUERY_ELEMENT_NAME = "appendblock";
+
private static final String BLOCK_QUERY_ELEMENT_NAME = "block";
private static final String BLOCK_ID_QUERY_ELEMENT_NAME = "blockid";
@@ -150,6 +152,49 @@ private static void addSnapshot(final UriQueryBuilder builder, final String snap
builder.add(Constants.QueryConstants.SNAPSHOT, snapshotVersion);
}
}
+
+ /**
+ * Constructs a web request to commit a block to an append blob.
+ *
+ * @param uri
+ * A java.net.URI
object that specifies the absolute URI.
+ * @param blobOptions
+ * A {@link BlobRequestOptions} object that specifies execution options such as retry policy and timeout
+ * settings for the operation. Specify null
to use the request options specified on the
+ * {@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.
+ * @param accessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the blob.
+ * @return a HttpURLConnection to use to perform the operation.
+ * @throws IOException
+ * if there is an error opening the connection
+ * @throws URISyntaxException
+ * if the resource URI is invalid
+ * @throws StorageException
+ * an exception representing any error which occurred during the operation.
+ */
+ public static HttpURLConnection appendBlock(final URI uri, final BlobRequestOptions blobOptions,
+ final OperationContext opContext, final AccessCondition accessCondition)
+ throws StorageException, IOException, URISyntaxException
+ {
+ final UriQueryBuilder builder = new UriQueryBuilder();
+ builder.add(Constants.QueryConstants.COMPONENT, APPEND_BLOCK_QUERY_ELEMENT_NAME);
+
+ final HttpURLConnection request = createURLConnection(uri, builder, blobOptions, opContext);
+
+ request.setDoOutput(true);
+ request.setRequestMethod(Constants.HTTP_PUT);
+
+ if (accessCondition != null) {
+ accessCondition.applyConditionToRequest(request);
+ accessCondition.applyAppendConditionToRequest(request);
+ }
+
+ return request;
+ }
/**
* Creates a request to copy a blob, Sign with 0 length.
@@ -701,14 +746,26 @@ private static HttpURLConnection lease(final URI uri, final BlobRequestOptions b
request.setFixedLengthStreamingMode(0);
request.setRequestProperty(HeaderConstants.LEASE_ACTION_HEADER, action.toString());
- request.setRequestProperty(HeaderConstants.LEASE_DURATION, leaseTimeInSeconds == null ? "-1"
- : leaseTimeInSeconds.toString());
+ // Lease duration should only be sent for acquire.
+ if (action == LeaseAction.ACQUIRE) {
+ // Assert lease duration is in bounds
+ if (leaseTimeInSeconds != null && leaseTimeInSeconds != -1) {
+ Utility.assertInBounds("leaseTimeInSeconds", leaseTimeInSeconds, Constants.LEASE_DURATION_MIN,
+ Constants.LEASE_DURATION_MAX);
+ }
+
+ request.setRequestProperty(HeaderConstants.LEASE_DURATION, leaseTimeInSeconds == null ? "-1"
+ : leaseTimeInSeconds.toString());
+ }
if (proposedLeaseId != null) {
request.setRequestProperty(HeaderConstants.PROPOSED_LEASE_ID_HEADER, proposedLeaseId);
}
if (breakPeriodInSeconds != null) {
+ // Assert lease break period is in bounds
+ Utility.assertInBounds("breakPeriodInSeconds", breakPeriodInSeconds, Constants.LEASE_BREAK_PERIOD_MIN,
+ Constants.LEASE_BREAK_PERIOD_MAX);
request.setRequestProperty(HeaderConstants.LEASE_BREAK_PERIOD_HEADER, breakPeriodInSeconds.toString());
}
@@ -1013,9 +1070,14 @@ public static HttpURLConnection putBlob(final URI uri, final BlobRequestOptions
properties.setLength(pageBlobSize);
}
- else {
+ else if (blobType == BlobType.BLOCK_BLOB){
request.setRequestProperty(BlobConstants.BLOB_TYPE_HEADER, BlobConstants.BLOCK_BLOB);
}
+ else if (blobType == BlobType.APPEND_BLOB){
+ request.setFixedLengthStreamingMode(0);
+ request.setRequestProperty(BlobConstants.BLOB_TYPE_HEADER, BlobConstants.APPEND_BLOB);
+ request.setRequestProperty(Constants.HeaderConstants.CONTENT_LENGTH, "0");
+ }
if (accessCondition != null) {
accessCondition.applyConditionToRequest(request);
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequestOptions.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequestOptions.java
index 61205a9c0ecb4..d1a2db160211c 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequestOptions.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobRequestOptions.java
@@ -26,9 +26,14 @@
public final class BlobRequestOptions extends RequestOptions {
/**
- * Represents the concurrent number of simultaneous requests per operation. If it's null, it will be set to the
- * value specified by the cloud blob client's default request options
- * {@link CloudBlobClient#getDefaultRequestOptions} during upload operations.
+ * Indicates whether a conditional failure should be absorbed on a retry attempt for the request. This option
+ * is only used by {@link CloudAppendBlob} in upload and openWrite methods. By default, it is set to
+ * false
. Set this to true
only for single writer scenario.
+ */
+ private Boolean absorbConditionalErrorsOnRetry = null;
+
+ /**
+ * Represents the concurrent number of simultaneous requests per operation. The default value is 1.
*/
private Integer concurrentRequestCount = null;
@@ -72,6 +77,7 @@ public BlobRequestOptions() {
public BlobRequestOptions(final BlobRequestOptions other) {
super(other);
if (other != null) {
+ this.setAbsorbConditionalErrorsOnRetry(other.getAbsorbConditionalErrorsOnRetry());
this.setConcurrentRequestCount(other.getConcurrentRequestCount());
this.setUseTransactionalContentMD5(other.getUseTransactionalContentMD5());
this.setStoreBlobContentMD5(other.getStoreBlobContentMD5());
@@ -94,9 +100,9 @@ public BlobRequestOptions(final BlobRequestOptions other) {
* {@link #concurrentRequestCount} field's value is null, it will be set to the value specified by the
* cloud blob client's {@link CloudBlobClient#getConcurrentRequestCount} method.
*/
- protected static final BlobRequestOptions applyDefaults(final BlobRequestOptions options, final BlobType blobType,
- final CloudBlobClient client) {
- return BlobRequestOptions.applyDefaults(options, blobType, client, true);
+ protected static final BlobRequestOptions populateAndApplyDefaults(final BlobRequestOptions options,
+ final BlobType blobType, final CloudBlobClient client) {
+ return BlobRequestOptions.populateAndApplyDefaults(options, blobType, client, true);
}
/**
@@ -115,20 +121,34 @@ protected static final BlobRequestOptions applyDefaults(final BlobRequestOptions
* @param setStartTime
* whether to initialize the startTimeInMs field, or not
*/
- protected static final BlobRequestOptions applyDefaults(final BlobRequestOptions options, final BlobType blobType,
- final CloudBlobClient client, final boolean setStartTime) {
+ protected static final BlobRequestOptions populateAndApplyDefaults(final BlobRequestOptions options,
+ final BlobType blobType, final CloudBlobClient client, final boolean setStartTime) {
BlobRequestOptions modifiedOptions = new BlobRequestOptions(options);
BlobRequestOptions.populateRequestOptions(modifiedOptions, client.getDefaultRequestOptions(), setStartTime);
- return BlobRequestOptions.applyDefaultsInternal(modifiedOptions, blobType, client);
+ BlobRequestOptions.applyDefaults(modifiedOptions, blobType);
+ return modifiedOptions;
}
- private static final BlobRequestOptions applyDefaultsInternal(final BlobRequestOptions modifiedOptions,
- final BlobType blobtype, final CloudBlobClient client) {
+ /**
+ * Applies defaults to the options passed in.
+ *
+ * @param modifiedOptions
+ * The options to apply defaults to.
+ */
+ protected static void applyDefaults(final BlobRequestOptions modifiedOptions, final BlobType blobtype) {
Utility.assertNotNull("modifiedOptions", modifiedOptions);
RequestOptions.applyBaseDefaultsInternal(modifiedOptions);
- if (modifiedOptions.getConcurrentRequestCount() == null) {
- modifiedOptions.setConcurrentRequestCount(BlobConstants.DEFAULT_CONCURRENT_REQUEST_COUNT);
+
+ if (modifiedOptions.getAbsorbConditionalErrorsOnRetry() == null) {
+ modifiedOptions.setAbsorbConditionalErrorsOnRetry(false);
}
+
+ if (blobtype == BlobType.APPEND_BLOB) {
+ // Append blobs must be done in serial.
+ modifiedOptions.setConcurrentRequestCount(1);
+ } else if (modifiedOptions.getConcurrentRequestCount() == null) {
+ modifiedOptions.setConcurrentRequestCount(BlobConstants.DEFAULT_CONCURRENT_REQUEST_COUNT);
+ }
if (modifiedOptions.getSingleBlobPutThresholdInBytes() == null) {
modifiedOptions.setSingleBlobPutThresholdInBytes(BlobConstants.DEFAULT_SINGLE_BLOB_PUT_THRESHOLD_IN_BYTES);
@@ -139,22 +159,27 @@ private static final BlobRequestOptions applyDefaultsInternal(final BlobRequestO
}
if (modifiedOptions.getStoreBlobContentMD5() == null) {
- modifiedOptions.setStoreBlobContentMD5(blobtype == BlobType.BLOCK_BLOB);
+ if (blobtype != BlobType.UNSPECIFIED) {
+ modifiedOptions.setStoreBlobContentMD5(blobtype == BlobType.BLOCK_BLOB);
+ }
}
if (modifiedOptions.getDisableContentMD5Validation() == null) {
modifiedOptions.setDisableContentMD5Validation(false);
}
-
- return modifiedOptions;
}
/**
* Populates any null fields in the first requestOptions object with values from the second requestOptions object.
*/
- private static final BlobRequestOptions populateRequestOptions(BlobRequestOptions modifiedOptions,
+ private static void populateRequestOptions(BlobRequestOptions modifiedOptions,
final BlobRequestOptions clientOptions, final boolean setStartTime) {
RequestOptions.populateRequestOptions(modifiedOptions, clientOptions, setStartTime);
+
+ if (modifiedOptions.getAbsorbConditionalErrorsOnRetry() == null) {
+ modifiedOptions.setAbsorbConditionalErrorsOnRetry(clientOptions.getAbsorbConditionalErrorsOnRetry());
+ }
+
if (modifiedOptions.getConcurrentRequestCount() == null) {
modifiedOptions.setConcurrentRequestCount(clientOptions.getConcurrentRequestCount());
}
@@ -174,10 +199,18 @@ private static final BlobRequestOptions populateRequestOptions(BlobRequestOption
if (modifiedOptions.getDisableContentMD5Validation() == null) {
modifiedOptions.setDisableContentMD5Validation(clientOptions.getDisableContentMD5Validation());
}
-
- return modifiedOptions;
}
+ /**
+ * Indicates whether a conditional failure should be absorbed on a retry attempt for the request. For more
+ * information about absorb conditinal errors on retry defaults, see {@link #setAbsorbConditionalErrorsOnRetry(Boolean)}.
+ *
+ * @return the absorbConditionalErrorsOnRetry
+ */
+ public Boolean getAbsorbConditionalErrorsOnRetry() {
+ return this.absorbConditionalErrorsOnRetry;
+ }
+
/**
* Gets the concurrent number of simultaneous requests per operation. For more information about concurrent request
* count defaults, see {@link #setConcurrentRequestCount(Integer)}.
@@ -232,12 +265,28 @@ public Integer getSingleBlobPutThresholdInBytes() {
return this.singleBlobPutThresholdInBytes;
}
+ /**
+ * Sets whether a conditional failure should be absorbed on a retry attempt for the request. This option
+ * is only used by {@link CloudAppendBlob} in upload and openWrite methods. By default, it is set to
+ * false
. Set this to true
only for single writer scenario.
+ * false
. You can
* change the useTransactionalContentMD5 value on this request by setting this property. You can also change the
- * value on the {@link BlobServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via
+ * value on the {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests made via
* the service client will use that useTransactionalContentMD5 value.
*
* @param useTransactionalContentMD5
@@ -269,7 +318,7 @@ public void setUseTransactionalContentMD5(final Boolean useTransactionalContentM
* true
for block blobs.
* You can change the storeBlobContentMD5 value on this request by setting this property. You can also change the
- * value on the {@link BlobServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via
+ * value on the {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests made via
* the service client will use that storeBlobContentMD5 value.
*
* @param storeBlobContentMD5
@@ -284,7 +333,7 @@ public void setStoreBlobContentMD5(final Boolean storeBlobContentMD5) {
* false
. You can
* change the disableContentMD5Validation value on this request by setting this property. You can also change the
- * value on the {@link BlobServiceClient#getDefaultRequestOptions()} object so that all subsequent requests made via
+ * value on the {@link CloudBlobClient#getDefaultRequestOptions()} object so that all subsequent requests made via
* the service client will use that disableContentMD5Validation value.
*
* @param disableContentMD5Validation
@@ -299,7 +348,7 @@ public void setDisableContentMD5Validation(final Boolean disableContentMD5Valida
* CloudAppendBlob
class using the specified absolute URI and storage service
+ * client.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object which represents the absolute URI to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final URI blobAbsoluteUri) throws StorageException {
+ this(new StorageUri(blobAbsoluteUri));
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified absolute URI and storage service
+ * client.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object which represents the absolute URI to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final StorageUri blobAbsoluteUri) throws StorageException {
+ this(blobAbsoluteUri, (StorageCredentials)null);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class by copying values from another append blob.
+ *
+ * @param otherBlob
+ * A CloudAppendBlob
object which represents the append blob to copy.
+ */
+ public CloudAppendBlob(final CloudAppendBlob otherBlob) {
+ super(otherBlob);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified absolute URI and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final URI blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified absolute URI, snapshot ID, and
+ * credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final URI blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), snapshotID, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified absolute StorageUri
+ * and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final StorageUri blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(blobAbsoluteUri, null /* snapshotID */, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified absolute StorageUri, snapshot
+ * ID, and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudAppendBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ super(BlobType.APPEND_BLOB, blobAbsoluteUri, snapshotID, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudAppendBlob
class using the specified URI, snapshot ID, and cloud blob
+ * client.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object which represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
which represents the snapshot version, if applicable.
+ * @param client
+ * A {@link CloudBlobContainer} object which represents the container to use for the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ protected CloudAppendBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final CloudBlobClient client)
+ throws StorageException {
+ super(BlobType.APPEND_BLOB, blobAbsoluteUri, snapshotID, client);
+ }
+
+ /**
+ * Requests the service to start copying a append blob's contents, properties, and metadata to a new append blob.
+ *
+ * @param sourceBlob
+ * A CloudAppendBlob
object that represents the source blob to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudAppendBlob sourceBlob) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceBlob, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a append blob's contents, properties, and metadata to a new append blob,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceBlob
+ * A CloudAppendBlob
object that represents the source blob to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source blob.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudAppendBlob sourceBlob, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceBlob", sourceBlob);
+ return this.startCopy(
+ sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
+
+ /**
+ * Creates an empty append blob. If the blob already exists, this will replace it.
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void createOrReplace(final AccessCondition accessCondition, BlobRequestOptions options,
+ OperationContext opContext) throws StorageException {
+ assertNoWriteOperationForSnapshot();
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.APPEND_BLOB, this.blobServiceClient);
+
+ ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
+ this.createImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
+ }
+
+ private StorageRequestlong
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ *
+ * @return The offset at which the block was appended.
+ * @throws IOException
+ * If an I/O exception occurred.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public Long appendBlock(final InputStream sourceStream, final long length) throws IOException, StorageException
+ {
+ return this.appendBlock(sourceStream, length, null, null, null);
+ }
+
+ /**
+ * Commits a new block of data to the end of the blob.
+ *
+ * @param sourceStream
+ * An {@link InputStream} object that represents the input stream to write to the Append blob.
+ * @param length
+ * A long
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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 The offset at which the block was appended.
+ * @throws IOException
+ * If an I/O exception occurred.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public Long appendBlock(final InputStream sourceStream, final long length, final AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException, IOException
+ {
+ if (length < -1) {
+ throw new IllegalArgumentException(SR.STREAM_LENGTH_NEGATIVE);
+ }
+
+ assertNoWriteOperationForSnapshot();
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.APPEND_BLOB, this.blobServiceClient);
+
+ if (sourceStream.markSupported()) {
+ // Mark sourceStream for current position.
+ sourceStream.mark(Constants.MAX_MARK_LENGTH);
+ }
+
+ InputStream bufferedStreamReference = sourceStream;
+ StreamMd5AndLength descriptor = new StreamMd5AndLength();
+ descriptor.setLength(length);
+
+ if (!sourceStream.markSupported()) {
+ // needs buffering
+ final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ descriptor = Utility.writeToOutputStream(sourceStream, byteStream, length, false /* rewindSourceStream */,
+ options.getUseTransactionalContentMD5(), opContext, options);
+
+ bufferedStreamReference = new ByteArrayInputStream(byteStream.toByteArray());
+ }
+ else if (length < 0 || options.getUseTransactionalContentMD5()) {
+ // If the stream is of unknown length or we need to calculate the
+ // MD5, then we we need to read the stream contents first
+ descriptor = Utility.analyzeStream(sourceStream, length, -1L, true /* rewindSourceStream */,
+ options.getUseTransactionalContentMD5());
+ }
+
+ if (descriptor.getLength() > 4 * Constants.MB) {
+ throw new IllegalArgumentException(SR.STREAM_LENGTH_GREATER_THAN_4MB);
+ }
+
+ StorageRequesttrue
is acceptable for you.
+ *
+ * @param sourceStream
+ * A {@link InputStream} object providing the blob content to append.
+ * @param length
+ * A long
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ @DoesServiceRequest
+ public void append(InputStream sourceStream, final long length) throws StorageException, IOException
+ {
+ this.append(sourceStream, length, null /* accessCondition */, null /* options */, null /* operationContext */);
+ }
+
+ /**
+ * Appends a stream to an append blob. This API should be used strictly in a single writer scenario because the API
+ * internally uses the append-offset conditional header to avoid duplicate blocks which does not work in a multiple
+ * writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param sourceStream
+ * A {@link InputStream} object providing the blob content to append.
+ * @param length
+ * A long
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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.
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ @DoesServiceRequest
+ public void append(InputStream sourceStream, final long length, AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException, IOException
+ {
+ assertNoWriteOperationForSnapshot();
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.APPEND_BLOB, this.blobServiceClient);
+
+ if (sourceStream.markSupported()) {
+ // Mark sourceStream for current position.
+ sourceStream.mark(Constants.MAX_MARK_LENGTH);
+ }
+
+ final BlobOutputStream streamRef = this.openWriteExisting(accessCondition, options, opContext);
+ try {
+ streamRef.write(sourceStream, length);
+ }
+ finally {
+ streamRef.close();
+ }
+ }
+
+ /**
+ * Appends the contents of a byte array to an append blob.This API should be used strictly in a single writer
+ * scenario because the API internally uses the append-offset conditional header to avoid duplicate blocks which
+ * does not work in a multiple writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param buffer
+ * A byte
array which represents the data to append to the blob.
+ * @param offset
+ * A int
which represents the offset of the byte array from which to start the data upload.
+ * @param length
+ * An int
which represents the number of bytes to upload from the input buffer.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendFromByteArray(final byte[] buffer, final int offset, final int length) throws StorageException,
+ IOException {
+ appendFromByteArray(buffer, offset, length, null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Appends the contents of a byte array to an append blob.This API should be used strictly in a single writer
+ * scenario because the API internally uses the append-offset conditional header to avoid duplicate blocks which
+ * does not work in a multiple writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param buffer
+ * A byte
array which represents the data to append to the blob.
+ * @param offset
+ * A int
which represents the offset of the byte array from which to start the data upload.
+ * @param length
+ * An int
which represents the number of bytes to upload from the input buffer.
+ * @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
+ * null
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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendFromByteArray(final byte[] buffer, final int offset, final int length,
+ final AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException, IOException {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer, offset, length);
+ this.append(inputStream, length, accessCondition, options, opContext);
+ inputStream.close();
+ }
+
+ /**
+ * Appends a file to an append blob. This API should be used strictly in a single writer scenario because the API
+ * internally uses the append-offset conditional header to avoid duplicate blocks which does not work in a multiple
+ * writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param path
+ * A String
which represents the path to the file to be appended.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendFromFile(final String path) throws StorageException, IOException {
+ appendFromFile(path, null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Appends a file to an append blob. This API should be used strictly in a single writer scenario because the API
+ * internally uses the append-offset conditional header to avoid duplicate blocks which does not work in a multiple
+ * writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param path
+ * A String
which represents the path to the file to be appended.
+ * @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
+ * null
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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendFromFile(final String path, final AccessCondition accessCondition, BlobRequestOptions options,
+ OperationContext opContext) throws StorageException, IOException {
+ File file = new File(path);
+ long fileLength = file.length();
+ InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
+ this.append(inputStream, fileLength, accessCondition, options, opContext);
+ inputStream.close();
+ }
+
+ /**
+ * Appends a string of text to an append blob using the platform's default encoding. This API should be used
+ * strictly in a single writer scenario because the API internally uses the append-offset conditional header to
+ * avoid duplicate blocks which does not work in a multiple writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param content
+ * A String
which represents the content that will be appended to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendText(final String content) throws StorageException, IOException {
+ this.appendText(content, null /* charsetName */, null /* accessCondition */, null /* options */,
+ null /* opContext */);
+ }
+
+ /**
+ * Appends a string of text to an append blob using the specified encoding. This API should be used strictly in a
+ * single writer scenario because the API internally uses the append-offset conditional header to avoid duplicate
+ * blocks which does not work in a multiple writer scenario.
+ * true
is acceptable for you.
+ *
+ * @param content
+ * A String
which represents the content that will be appended to the blob.
+ * @param charsetName
+ * A String
which represents the name of the charset to use to encode the content.
+ * If null, the platform's default encoding is used.
+ * @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
+ * null
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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws IOException
+ * If an I/O exception occurred.
+ */
+ public void appendText(final String content, final String charsetName, final AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException, IOException {
+ byte[] bytes = (charsetName == null) ? content.getBytes() : content.getBytes(charsetName);
+ this.appendFromByteArray(bytes, 0, bytes.length, accessCondition, options, opContext);
+ }
+
+ /**
+ * Opens an output stream object to write data to the append blob. The append blob must already exist and will be
+ * appended to.
+ * true
is acceptable for you.
+ *
+ * @return A {@link BlobOutputStream} object used to write data to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public BlobOutputStream openWriteExisting() throws StorageException {
+ return this.openWriteExisting(null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Opens an output stream object to write data to the append blob, using the specified lease ID, request options and
+ * operation context. The append blob must already exist and will be appended to.
+ * true
is acceptable for you.
+ *
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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 BlobOutputStream} object used to write data to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public BlobOutputStream openWriteExisting(AccessCondition accessCondition, BlobRequestOptions options,
+ OperationContext opContext) throws StorageException {
+ return this.openOutputStreamInternal(false, accessCondition, options, opContext);
+ }
+
+ /**
+ * Opens an output stream object to write data to the append blob. The append blob does not need to yet exist. If
+ * the blob already exists, this will replace it.
+ * true
is acceptable for you.
+ *
+ * @return A {@link BlobOutputStream} object used to write data to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public BlobOutputStream openWriteNew() throws StorageException {
+ return this.openWriteNew(null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Opens an output stream object to write data to the append blob, using the specified lease ID, request options and
+ * operation context. The append blob does not need to yet exist. If the blob already exists, this will replace it.
+ * true
is acceptable for you.
+ *
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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 BlobOutputStream} object used to write data to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public BlobOutputStream openWriteNew(AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException {
+ return this.openOutputStreamInternal(true, accessCondition, options, opContext);
+ }
+
+ /**
+ * Opens an output stream object to write data to the append blob, using the specified lease ID, request options and
+ * operation context.
+ *
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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 BlobOutputStream} object used to write data to the blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ private BlobOutputStream openOutputStreamInternal(boolean create, AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException {
+ assertNoWriteOperationForSnapshot();
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ BlobRequestOptions modifiedOptions = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.APPEND_BLOB,
+ this.blobServiceClient, false /* setStartTime */);
+
+ if (create) {
+ this.createOrReplace(accessCondition, modifiedOptions, opContext);
+ } else {
+ if (modifiedOptions.getStoreBlobContentMD5()) {
+ throw new IllegalArgumentException(SR.APPEND_BLOB_MD5_NOT_POSSIBLE);
+ }
+
+ // Download attributes to check the etag and date access conditions and
+ // to get the blob length to verify the append position on the first write.
+ this.downloadAttributes(accessCondition, modifiedOptions, opContext);
+ }
+
+ // Use an access condition with the etag and date conditions removed as we will be
+ // appending to the blob and these properties will change each time we append a block.
+ AccessCondition appendCondition = new AccessCondition();
+ if (accessCondition != null) {
+ appendCondition.setLeaseID(accessCondition.getLeaseID());
+ appendCondition.setIfAppendPositionEqual(accessCondition.getIfAppendPositionEqual());
+ appendCondition.setIfMaxSizeLessThanOrEqual(accessCondition.getIfMaxSizeLessThanOrEqual());
+ }
+
+ return new BlobOutputStream(this, appendCondition, modifiedOptions, opContext);
+ }
+
+ /**
+ * Uploads the source stream data to the append blob. If the blob already exists on the service, it will be
+ * overwritten.
+ * true
is acceptable for you.
+ *
+ * @param sourceStream
+ * An {@link InputStream} object to read from.
+ * @param length
+ * A long
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ *
+ * @throws IOException
+ * If an I/O exception occurred.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @Override
+ @DoesServiceRequest
+ public void upload(final InputStream sourceStream, final long length) throws StorageException, IOException {
+ this.upload(sourceStream, length, null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Uploads the source stream data to the append blob using the specified lease ID, request options, and operation
+ * context. If the blob already exists on the service, it will be overwritten.
+ * true
is acceptable for you.
+ *
+ * @param sourceStream
+ * An {@link InputStream} object to read from.
+ * @param length
+ * A long
which represents the length, in bytes, of the stream data, or -1 if unknown.
+ * @param accessCondition
+ * An {@link AccessCondition} object which represents the access conditions for the blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudBlobClient}).
+ * @param opContext
+ * An {@link OperationContext} object which 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.
+ *
+ * @throws IOException
+ * If an I/O exception occurred.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @Override
+ @DoesServiceRequest
+ public void upload(final InputStream sourceStream, final long length, final AccessCondition accessCondition,
+ BlobRequestOptions options, OperationContext opContext) throws StorageException, IOException {
+ assertNoWriteOperationForSnapshot();
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.APPEND_BLOB, this.blobServiceClient);
+
+ if (sourceStream.markSupported()) {
+ // Mark sourceStream for current position.
+ sourceStream.mark(Constants.MAX_MARK_LENGTH);
+ }
+
+ final BlobOutputStream streamRef = this.openWriteNew(accessCondition, options, opContext);
+ try {
+ streamRef.write(sourceStream, length);
+ }
+ finally {
+ streamRef.close();
+ }
+ }
+
+ /**
+ * Sets the number of bytes to buffer when writing to a {@link BlobOutputStream}.
+ *
+ * @param streamWriteSizeInBytes
+ * An int
which represents the maximum block size, in bytes, for writing to an append blob
+ * while using a {@link BlobOutputStream} object, ranging from 16 KB to 4 MB, inclusive.
+ *
+ * @throws IllegalArgumentException
+ * If streamWriteSizeInBytes
is less than 16 KB or greater than 4 MB.
+ */
+ @Override
+ public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) {
+ if (streamWriteSizeInBytes > Constants.MAX_BLOCK_SIZE || streamWriteSizeInBytes < 16 * Constants.KB) {
+ throw new IllegalArgumentException("StreamWriteSizeInBytes");
+ }
+
+ this.streamWriteSizeInBytes = streamWriteSizeInBytes;
+ }
+}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java
index dac9d0bc3d801..62e12034be80a 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlob.java
@@ -40,6 +40,7 @@
import com.microsoft.azure.storage.DoesServiceRequest;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.SharedAccessPolicy;
+import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
@@ -67,7 +68,7 @@ public abstract class CloudBlob implements ListBlobItem {
/**
* Holds the metadata for the blob.
*/
- HashMapCloudBlob
class using the specified URI, snapshot ID, and cloud blob
* client.
@@ -187,7 +182,7 @@ protected CloudBlob(final BlobType type, final StorageUri uri, final CloudBlobCl
* @param snapshotID
* A String
that represents the snapshot version, if applicable.
* @param client
- * A {@link CloudBlobContainer} object that represents the container to use for the blob.
+ * A {@link CloudBlobClient} object that specifies the endpoint for the Blob service.
*
* @throws StorageException
* If a storage service error occurred.
@@ -204,6 +199,54 @@ protected CloudBlob(final BlobType type, final StorageUri uri, final String snap
}
}
}
+
+ /**
+ * Creates an instance of the CloudBlob
class using the specified URI and cloud blob client.
+ *
+ * @param type
+ * A {@link BlobType} value which represents the type of the blob.
+ * @param uri
+ * A {@link StorageUri} object that represents the URI to the blob, beginning with the container name.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ protected CloudBlob(final BlobType type, final StorageUri uri, final StorageCredentials credentials)
+ throws StorageException {
+ this(type, uri, null /* snapshotID */, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudBlob
class using the specified URI, snapshot ID, and cloud blob
+ * client.
+ *
+ * @param type
+ * A {@link BlobType} value which represents the type of the blob.
+ * @param uri
+ * A {@link StorageUri} object that represents the URI to the blob, beginning with the container name.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ protected CloudBlob(final BlobType type, final StorageUri uri, final String snapshotID,
+ final StorageCredentials credentials) throws StorageException {
+ this(type);
+ this.parseQueryAndVerify(uri, credentials);
+
+ if (snapshotID != null) {
+ if (this.snapshotID != null) {
+ throw new IllegalArgumentException(SR.SNAPSHOT_QUERY_OPTION_ALREADY_DEFINED);
+ }
+ else {
+ this.snapshotID = snapshotID;
+ }
+ }
+ }
/**
* Creates an instance of the CloudBlob
class by copying values from another blob.
@@ -212,7 +255,6 @@ protected CloudBlob(final BlobType type, final StorageUri uri, final String snap
* A CloudBlob
object that represents the blob to copy.
*/
protected CloudBlob(final CloudBlob otherBlob) {
- this.metadata = new HashMapString
that represents the lease ID.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final String acquireLease() throws StorageException {
+ return this.acquireLease(null /* leaseTimeInSeconds */, null /* proposedLeaseId */);
+ }
+
/**
* Acquires a new lease on the blob with the specified lease time and proposed lease ID.
*
@@ -379,7 +434,7 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.acquireLeaseImpl(leaseTimeInSeconds, proposedLeaseId, accessCondition, options),
@@ -402,7 +457,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -434,12 +489,16 @@ protected final void assertCorrectBlobType() throws StorageException {
throw new StorageException(StorageErrorCodeStrings.INCORRECT_BLOB_TYPE, String.format(SR.INVALID_BLOB_TYPE,
BlobType.BLOCK_BLOB, this.properties.getBlobType()), Constants.HeaderConstants.HTTP_UNUSED_306,
null, null);
- }
- if (this instanceof CloudPageBlob && this.properties.getBlobType() != BlobType.PAGE_BLOB) {
+ }
+ else if (this instanceof CloudPageBlob && this.properties.getBlobType() != BlobType.PAGE_BLOB) {
throw new StorageException(StorageErrorCodeStrings.INCORRECT_BLOB_TYPE, String.format(SR.INVALID_BLOB_TYPE,
BlobType.PAGE_BLOB, this.properties.getBlobType()), Constants.HeaderConstants.HTTP_UNUSED_306,
null, null);
-
+ }
+ else if (this instanceof CloudAppendBlob && this.properties.getBlobType() != BlobType.APPEND_BLOB) {
+ throw new StorageException(StorageErrorCodeStrings.INCORRECT_BLOB_TYPE, String.format(SR.INVALID_BLOB_TYPE,
+ BlobType.APPEND_BLOB, this.properties.getBlobType()), Constants.HeaderConstants.HTTP_UNUSED_306,
+ null, null);
}
}
@@ -508,7 +567,7 @@ public final long breakLease(final Integer breakPeriodInSeconds, final AccessCon
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.breakLeaseImpl(breakPeriodInSeconds, accessCondition, options), options.getRetryPolicyFactory(),
@@ -531,7 +590,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -611,7 +670,7 @@ public final String changeLease(final String proposedLeaseId, final AccessCondit
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.changeLeaseImpl(proposedLeaseId, accessCondition, options), options.getRetryPolicyFactory(),
@@ -633,7 +692,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -664,7 +723,10 @@ public String preProcessResponse(CloudBlob blob, CloudBlobClient client, Operati
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
+ *
+ * @deprecated as of 3.0.0. Use {@link CloudBlob#startCopy(URI)} instead.
*/
+ @Deprecated
@DoesServiceRequest
public final String startCopyFromBlob(final CloudBlob sourceBlob) throws StorageException, URISyntaxException {
return this.startCopyFromBlob(sourceBlob, null /* sourceAccessCondition */,
@@ -695,83 +757,144 @@ public final String startCopyFromBlob(final CloudBlob sourceBlob) throws Storage
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
- *
+ *
+ * @deprecated as of 3.0.0. Use {@link CloudBlob#startCopy(
+ * URI, AccessCondition, AccessCondition, BlobRequestOptions, OperationContext)} instead.
*/
+ @Deprecated
@DoesServiceRequest
public final String startCopyFromBlob(final CloudBlob sourceBlob, final AccessCondition sourceAccessCondition,
final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
throws StorageException, URISyntaxException {
Utility.assertNotNull("sourceBlob", sourceBlob);
- return this.startCopyFromBlob(
+ return this.startCopy(
sourceBlob.getServiceClient().getCredentials().transformUri(sourceBlob.getQualifiedUri()),
sourceAccessCondition, destinationAccessCondition, options, opContext);
-
}
/**
- * Requests the service to start copying a blob's contents, properties, and metadata to a new blob.
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new blob.
*
* @param source
- * A java.net.URI
The URI of a source blob.
+ * A java.net.URI
The source URI. URIs for resources outside of Azure
+ * may only be copied into block blobs.
*
* @return A String
which represents the copy ID associated with the copy operation.
*
* @throws StorageException
- * If a storage service error occurred.
+ * If a storage service error occurred.
+ *
+ * @deprecated as of 3.0.0. Use {@link CloudBlob#startCopy(URI)} instead.
*/
+ @Deprecated
@DoesServiceRequest
public final String startCopyFromBlob(final URI source) throws StorageException {
- return this.startCopyFromBlob(source, null /* sourceAccessCondition */,
- null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ return this.startCopy(source, null /* sourceAccessCondition */, null /* destinationAccessCondition */,
+ null /* options */, null /* opContext */);
}
/**
- * Requests the service to start copying a blob's contents, properties, and metadata to a new blob, using the
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new blob, using the
* specified access conditions, lease ID, request options, and operation context.
*
* @param source
- * A java.net.URI
The URI of a source blob.
+ * A java.net.URI
The source URI. URIs for resources outside of Azure
+ * may only be copied into block blobs.
* @param sourceAccessCondition
- * An {@link AccessCondition} object that represents the access conditions for the source blob.
+ * An {@link AccessCondition} object that represents the access conditions for the source.
* @param destinationAccessCondition
- * An {@link AccessCondition} object that represents the access conditions for the destination blob.
+ * An {@link AccessCondition} object that represents the access conditions for the destination.
* @param options
- * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
- * null
will use the default request options from the associated service client (
- * {@link CloudBlobClient}).
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
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.
+ * 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 String
which represents the copy ID associated with the copy operation.
*
* @throws StorageException
- * If a storage service error occurred.
- *
+ * If a storage service error occurred.
+ *
+ * @deprecated as of 3.0.0. Use {@link CloudBlob#startCopy(
+ * URI, AccessCondition, AccessCondition, BlobRequestOptions, OperationContext)} instead.
*/
+ @Deprecated
@DoesServiceRequest
public final String startCopyFromBlob(final URI source, final AccessCondition sourceAccessCondition,
final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
throws StorageException {
+ return this.startCopy(source, sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
+
+ /**
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new blob.
+ *
+ * @param source
+ * A java.net.URI
The source URI. URIs for resources outside of Azure
+ * may only be copied into block blobs.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final String startCopy(final URI source) throws StorageException {
+ return this.startCopy(source, null /* sourceAccessCondition */, null /* destinationAccessCondition */,
+ null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new blob, using the
+ * specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param source
+ * A java.net.URI
The source URI. URIs for resources outside of Azure
+ * may only be copied into block blobs.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final URI source, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException {
if (opContext == null) {
opContext = new OperationContext();
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
- this.startCopyFromBlobImpl(source, sourceAccessCondition, destinationAccessCondition, options),
+ this.startCopyImpl(source, sourceAccessCondition, destinationAccessCondition, options),
options.getRetryPolicyFactory(), opContext);
}
- private StorageRequestbyte
array which represents the buffer to which the blob bytes are downloaded.
- * @param bufferOffet
+ * @param bufferOffset
* A long
which represents the byte offset to use as the starting point for the target.
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the blob.
@@ -1594,7 +1721,7 @@ public final int downloadToByteArray(final byte[] buffer, final int bufferOffset
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.downloadToByteArrayImpl(null, null, buffer, bufferOffset, accessCondition, options, opContext),
@@ -1636,7 +1763,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -1745,7 +1872,7 @@ public void recoveryAction(OperationContext context) throws IOException {
}
/**
- * Uploads a blob from data in a byte array.
+ * Uploads a blob from data in a byte array. If the blob already exists on the service, it will be overwritten.
*
* @param buffer
* A byte
array which represents the data to write to the blob.
@@ -1764,7 +1891,7 @@ public void uploadFromByteArray(final byte[] buffer, final int offset, final int
}
/**
- * Uploads a blob from data in a byte array.
+ * Uploads a blob from data in a byte array. If the blob already exists on the service, it will be overwritten.
*
* @param buffer
* A byte
array which represents the data to write to the blob.
@@ -1796,7 +1923,7 @@ public void uploadFromByteArray(final byte[] buffer, final int offset, final int
}
/**
- * Uploads a blob from a file.
+ * Uploads a blob from a file. If the blob already exists on the service, it will be overwritten.
*
* @param path
* A String
which represents the path to the file to be uploaded.
@@ -1810,7 +1937,7 @@ public void uploadFromFile(final String path) throws StorageException, IOExcepti
}
/**
- * Uploads a blob from a file.
+ * Uploads a blob from a file. If the blob already exists on the service, it will be overwritten.
*
* @param path
* A String
which represents the path to the file to be uploaded.
@@ -1955,7 +2082,7 @@ private final boolean exists(final boolean primaryOnly, final AccessCondition ac
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.existsImpl(primaryOnly, accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -1982,7 +2109,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -2061,7 +2188,7 @@ public String generateSharedAccessSignature(final SharedAccessBlobPolicy policy,
public String generateSharedAccessSignature(final SharedAccessBlobPolicy policy,
final SharedAccessBlobHeaders headers, final String groupPolicyIdentifier) throws InvalidKeyException,
StorageException {
-
+
if (!StorageCredentialsHelper.canCredentialsSignRequest(this.blobServiceClient.getCredentials())) {
throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
}
@@ -2072,10 +2199,10 @@ public String generateSharedAccessSignature(final SharedAccessBlobPolicy policy,
final String resourceName = this.getCanonicalName(true);
- final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlob(policy, headers,
- groupPolicyIdentifier, resourceName, this.blobServiceClient, null);
+ final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile(policy, headers,
+ groupPolicyIdentifier, resourceName, this.blobServiceClient);
- final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlob(policy,
+ final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile(policy,
headers, groupPolicyIdentifier, "b", signature);
return builder.toString();
@@ -2083,32 +2210,34 @@ public String generateSharedAccessSignature(final SharedAccessBlobPolicy policy,
/**
* Returns the canonical name of the blob in the format of
- * /<account-name>/<container-name>/<blob-name>.
+ * /<service-name>/<account-name>/<container-name>/<blob-name>.
* true
if the snapshot time is ignored; otherwise, false
.
*
- * @return The canonical name in the format of /<account-name>/<container
- * -name>/<blob-name>.
+ * @return The canonical name in the format of /<service-name>/<account-name>
+ * /<container-name>/<blob-name>.
*/
String getCanonicalName(final boolean ignoreSnapshotTime) {
- String canonicalName;
+ StringBuilder canonicalName = new StringBuilder("/");
+ canonicalName.append(SR.BLOB);
+
if (this.blobServiceClient.isUsePathStyleUris()) {
- canonicalName = this.getUri().getRawPath();
+ canonicalName.append(this.getUri().getRawPath());
}
else {
- canonicalName = PathUtility.getCanonicalPathFromCredentials(this.blobServiceClient.getCredentials(), this
- .getUri().getRawPath());
+ canonicalName.append(PathUtility.getCanonicalPathFromCredentials(
+ this.blobServiceClient.getCredentials(), this.getUri().getRawPath()));
}
if (!ignoreSnapshotTime && this.snapshotID != null) {
- canonicalName = canonicalName.concat("?snapshot=");
- canonicalName = canonicalName.concat(this.snapshotID);
+ canonicalName.append("?snapshot=");
+ canonicalName.append(this.snapshotID);
}
- return canonicalName;
+ return canonicalName.toString();
}
/**
@@ -2120,6 +2249,7 @@ String getCanonicalName(final boolean ignoreSnapshotTime) {
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
@Override
public final CloudBlobContainer getContainer() throws StorageException, URISyntaxException {
if (this.container == null) {
@@ -2149,9 +2279,6 @@ public final HashMapInputStream
object that represents the stream to use for reading from the blob.
*
@@ -2342,7 +2469,7 @@ public final BlobInputStream openInputStream() throws StorageException {
/**
* Opens a blob input stream to download the blob using the specified request options and operation context.
* true
if path-style URIs are used; otherwise, false
.
+ * A {@link StorageUri} object which represents the complete URI.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
* @throws StorageException
* If a storage service error occurred.
- * */
- protected void parseURIQueryStringAndVerify(final StorageUri completeUri, final CloudBlobClient existingClient,
- final boolean usePathStyleUris) throws StorageException {
- Utility.assertNotNull("resourceUri", completeUri);
+ */
+ private void parseQueryAndVerify(final StorageUri completeUri, final StorageCredentials credentials)
+ throws StorageException {
+ Utility.assertNotNull("completeUri", completeUri);
if (!completeUri.isAbsolute()) {
- final String errorMessage = String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString());
- throw new IllegalArgumentException(errorMessage);
+ throw new IllegalArgumentException(String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString()));
}
this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri);
-
+
final HashMapInputStream
object that represents the source stream to upload.
@@ -2726,7 +2837,8 @@ protected void updateLengthFromResponse(HttpURLConnection request) {
/**
* Uploads the source stream data to the blob using the specified lease ID, request options, and operation context.
- *
+ * If the blob already exists on the service, it will be overwritten.
+ *
* @param sourceStream
* An InputStream
object that represents the source stream to upload.
* @param length
@@ -2798,7 +2910,7 @@ public final void uploadMetadata(final AccessCondition accessCondition, BlobRequ
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.uploadMetadataImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -2824,7 +2936,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlob blob, OperationCo
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -2887,7 +2999,7 @@ public final void uploadProperties(final AccessCondition accessCondition, BlobRe
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.uploadPropertiesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -2909,7 +3021,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, Op
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobClient.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobClient.java
index c8febc24ad259..05841ca61b1fe 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobClient.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobClient.java
@@ -19,12 +19,10 @@
import java.net.URISyntaxException;
import com.microsoft.azure.storage.DoesServiceRequest;
-import com.microsoft.azure.storage.LocationMode;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.ResultContinuation;
import com.microsoft.azure.storage.ResultContinuationType;
import com.microsoft.azure.storage.ResultSegment;
-import com.microsoft.azure.storage.RetryExponentialRetry;
import com.microsoft.azure.storage.ServiceClient;
import com.microsoft.azure.storage.ServiceProperties;
import com.microsoft.azure.storage.ServiceStats;
@@ -56,7 +54,7 @@ public final class CloudBlobClient extends ServiceClient {
/**
* Holds the default request option values associated with this Service Client.
*/
- private BlobRequestOptions defaultRequestOptions;
+ private BlobRequestOptions defaultRequestOptions = new BlobRequestOptions();
/**
* Creates an instance of the CloudBlobClient
class using the specified Blob service endpoint and
@@ -108,26 +106,7 @@ public CloudBlobClient(final URI baseUri, StorageCredentials credentials) {
*/
public CloudBlobClient(final StorageUri storageUri, StorageCredentials credentials) {
super(storageUri, credentials);
- this.defaultRequestOptions = new BlobRequestOptions();
- this.defaultRequestOptions.setLocationMode(LocationMode.PRIMARY_ONLY);
- this.defaultRequestOptions.setRetryPolicyFactory(new RetryExponentialRetry());
- this.defaultRequestOptions.setConcurrentRequestCount(BlobConstants.DEFAULT_CONCURRENT_REQUEST_COUNT);
- this.defaultRequestOptions.setDisableContentMD5Validation(false);
- this.defaultRequestOptions
- .setSingleBlobPutThresholdInBytes(BlobConstants.DEFAULT_SINGLE_BLOB_PUT_THRESHOLD_IN_BYTES);
- this.defaultRequestOptions.setUseTransactionalContentMD5(false);
- }
-
- /**
- * Returns the number of maximum concurrent requests allowed.
- *
- * @return The number of maximum concurrent requests allowed.
- *
- * @deprecated use {@link #getDefaultRequestOptions().getConcurrentRequestCount()} instead.
- */
- @Deprecated
- public int getConcurrentRequestCount() {
- return this.defaultRequestOptions.getConcurrentRequestCount();
+ BlobRequestOptions.applyDefaults(this.defaultRequestOptions, BlobType.UNSPECIFIED);
}
/**
@@ -149,6 +128,7 @@ public int getConcurrentRequestCount() {
* @see Naming and Referencing Containers, Blobs,
* and Metadata
*/
+ @SuppressWarnings("deprecation")
public CloudBlobContainer getContainerReference(final String containerName) throws URISyntaxException,
StorageException {
return new CloudBlobContainer(containerName, this);
@@ -163,21 +143,6 @@ public String getDirectoryDelimiter() {
return this.directoryDelimiter;
}
- /**
- * Returns the threshold size used for writing a single blob for this Blob service client.
- *
- * @return The maximum size, in bytes, of a blob that may be uploaded as a single blob, ranging from 1 to 64 MB
- * inclusive. The default value is 32 MBs.
- * int
which specifies the maximum size, in bytes, of a blob that may be uploaded as a
- * single
- * blob, ranging from 1 MB to 64 MB inclusive. If a blob size is above the threshold, it will be uploaded
- * as blocks.
- *
- * @throws IllegalArgumentException
- * If minimumReadSize
is less than 1 MB or greater than 64 MB.
- *
- * @deprecated use {@link #getDefaultRequestOptions().setSingleBlobPutThresholdInBytes()} instead.
- */
- @Deprecated
- public void setSingleBlobPutThresholdInBytes(final int singleBlobPutThresholdInBytes) {
- this.defaultRequestOptions.setSingleBlobPutThresholdInBytes(singleBlobPutThresholdInBytes);
- }
-
/**
* Gets the {@link BlobRequestOptions} that is used for requests associated with this CloudBlobClient
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java
index 1dea8bf3710e3..73cd903a3a569 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobContainer.java
@@ -37,6 +37,7 @@
import com.microsoft.azure.storage.ResultSegment;
import com.microsoft.azure.storage.SharedAccessPolicyHandler;
import com.microsoft.azure.storage.SharedAccessPolicySerializer;
+import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
@@ -94,12 +95,12 @@ else if ("blob".equals(lowerAclString)) {
/**
* Represents the container metadata.
*/
- protected HashMapCloudBlobContainer
class using the specified URI. The blob URI should
* include a SAS token unless anonymous access is to be used.
@@ -137,10 +126,8 @@ private CloudBlobContainer(final CloudBlobClient client) {
*
* @throws StorageException
* If a storage service error occurred.
- * @throws URISyntaxException
- * If the resource URI is invalid.
*/
- public CloudBlobContainer(final URI uri) throws URISyntaxException, StorageException {
+ public CloudBlobContainer(final URI uri) throws StorageException {
this(new StorageUri(uri));
}
@@ -153,11 +140,40 @@ public CloudBlobContainer(final URI uri) throws URISyntaxException, StorageExcep
*
* @throws StorageException
* If a storage service error occurred.
- * @throws URISyntaxException
- * If the resource URI is invalid.
*/
- public CloudBlobContainer(final StorageUri storageUri) throws URISyntaxException, StorageException {
- this(storageUri, (CloudBlobClient) null /* client */);
+ public CloudBlobContainer(final StorageUri storageUri) throws StorageException {
+ this(storageUri, (StorageCredentials) null);
+ }
+
+ /**
+ * Creates an instance of the CloudBlobContainer
class using the specified URI and credentials.
+ *
+ * @param uri
+ * A java.net.URI
object that represents the absolute URI of the container.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlobContainer(final URI uri, final StorageCredentials credentials) throws StorageException {
+ this(new StorageUri(uri), credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudBlobContainer
class using the specified StorageUri and credentials.
+ *
+ * @param storageUri
+ * A {@link StorageUri} object which represents the absolute StorageUri of the container.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlobContainer(final StorageUri storageUri, final StorageCredentials credentials)
+ throws StorageException {
+ this.parseQueryAndVerify(storageUri, credentials);
}
/**
@@ -180,19 +196,19 @@ public CloudBlobContainer(final StorageUri storageUri) throws URISyntaxException
*
* @see Naming and Referencing Containers, Blobs,
* and Metadata
+ * @deprecated as of 3.0.0. Please use {@link CloudBlobClient#getContainerReference(String)}
*/
+ @Deprecated
public CloudBlobContainer(final String containerName, final CloudBlobClient client) throws URISyntaxException,
StorageException {
- this(client);
Utility.assertNotNull("client", client);
Utility.assertNotNull("containerName", containerName);
this.storageUri = PathUtility.appendPathToUri(client.getStorageUri(), containerName);
-
this.name = containerName;
- this.parseQueryAndVerify(this.storageUri, client, client.isUsePathStyleUris());
+ this.blobServiceClient = client;
}
-
+
/**
* Creates an instance of the CloudBlobContainer
class using the specified URI and client.
*
@@ -206,7 +222,9 @@ public CloudBlobContainer(final String containerName, final CloudBlobClient clie
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlobContainer#CloudBlobContainer(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudBlobContainer(final URI uri, final CloudBlobClient client) throws URISyntaxException, StorageException {
this(new StorageUri(uri), client);
}
@@ -224,21 +242,17 @@ public CloudBlobContainer(final URI uri, final CloudBlobClient client) throws UR
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlobContainer#CloudBlobContainer(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudBlobContainer(final StorageUri storageUri, final CloudBlobClient client) throws URISyntaxException,
StorageException {
- this(client);
-
- Utility.assertNotNull("storageUri", storageUri);
-
- this.storageUri = storageUri;
-
- boolean usePathStyleUris = client == null ? Utility.determinePathStyleFromUri(this.storageUri.getPrimaryUri())
- : client.isUsePathStyleUris();
-
- this.name = PathUtility.getContainerNameFromUri(storageUri.getPrimaryUri(), usePathStyleUris);
+ this.parseQueryAndVerify(storageUri, client == null ? null : client.getCredentials());
- this.parseQueryAndVerify(this.storageUri, client, usePathStyleUris);
+ // Override the client set in parseQueryAndVerify to make sure request options are propagated.
+ if (client != null) {
+ this.blobServiceClient = client;
+ }
}
/**
@@ -274,7 +288,7 @@ public void create(BlobRequestOptions options, OperationContext opContext) throw
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this, createImpl(options),
options.getRetryPolicyFactory(), opContext);
@@ -300,7 +314,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlobContainer containe
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -355,7 +369,7 @@ public boolean createIfNotExists() throws StorageException {
*/
@DoesServiceRequest
public boolean createIfNotExists(BlobRequestOptions options, OperationContext opContext) throws StorageException {
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
boolean exists = this.exists(true /* primaryOnly */, null /* accessCondition */, options, opContext);
if (exists) {
@@ -414,7 +428,7 @@ public void delete(AccessCondition accessCondition, BlobRequestOptions options,
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this, deleteImpl(accessCondition, options),
options.getRetryPolicyFactory(), opContext);
@@ -434,7 +448,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -486,7 +500,7 @@ public boolean deleteIfExists() throws StorageException {
@DoesServiceRequest
public boolean deleteIfExists(AccessCondition accessCondition, BlobRequestOptions options,
OperationContext opContext) throws StorageException {
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
boolean exists = this.exists(true /* primaryOnly */, accessCondition, options, opContext);
if (exists) {
@@ -546,7 +560,7 @@ public void downloadAttributes(AccessCondition accessCondition, BlobRequestOptio
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.downloadAttributesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -573,7 +587,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -637,7 +651,7 @@ public BlobContainerPermissions downloadPermissions(AccessCondition accessCondit
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
downloadPermissionsImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -663,7 +677,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -744,7 +758,7 @@ private boolean exists(final boolean primaryOnly, final AccessCondition accessCo
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.existsImpl(primaryOnly, accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -772,7 +786,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, -1L, context);
}
@Override
@@ -822,34 +836,74 @@ public String generateSharedAccessSignature(final SharedAccessBlobPolicy policy,
final String resourceName = this.getSharedAccessCanonicalName();
- final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlob(policy,
- null /* SharedAccessBlobHeaders */, groupPolicyIdentifier, resourceName, this.blobServiceClient, null);
+ final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile(policy,
+ null /* SharedAccessBlobHeaders */, groupPolicyIdentifier, resourceName, this.blobServiceClient);
- final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlob(policy,
+ final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile(policy,
null /* SharedAccessBlobHeaders */, groupPolicyIdentifier, "c", signature);
return builder.toString();
}
/**
- * Returns a reference to a {@link CloudBlockBlob} object that represents a block blob in this container.
+ * Returns a reference to a {@link CloudAppendBlob} object that represents an append blob in this container.
*
* @param blobName
* A String
that represents the name of the blob.
*
- * @return A {@link CloudBlockBlob} object that represents a reference to the specified block blob.
+ * @return A {@link CloudAppendBlob} object that represents a reference to the specified append blob.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
- public CloudBlockBlob getBlockBlobReference(final String blobName) throws URISyntaxException, StorageException {
+ public CloudAppendBlob getAppendBlobReference(final String blobName) throws URISyntaxException, StorageException {
+ return this.getAppendBlobReference(blobName, null);
+ }
+
+ /**
+ * Returns a reference to a {@link CloudAppendBlob} object that represents an append blob in the container, using the
+ * specified snapshot ID.
+ *
+ * @param blobName
+ * A String
that represents the name of the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot ID of the blob.
+ *
+ * @return A {@link CloudAppendBlob} object that represents a reference to the specified append blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ * If the resource URI is invalid.
+ */
+ public CloudAppendBlob getAppendBlobReference(final String blobName, final String snapshotID)
+ throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("blobName", blobName);
final StorageUri address = PathUtility.appendPathToUri(this.storageUri, blobName);
- return new CloudBlockBlob(address, this.blobServiceClient, this);
+ final CloudAppendBlob retBlob = new CloudAppendBlob(address, snapshotID, this.blobServiceClient);
+ retBlob.setContainer(this);
+ return retBlob;
+ }
+
+ /**
+ * Returns a reference to a {@link CloudBlockBlob} object that represents a block blob in this container.
+ *
+ * @param blobName
+ * A String
that represents the name of the blob.
+ *
+ * @return A {@link CloudBlockBlob} object that represents a reference to the specified block blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ * If the resource URI is invalid.
+ */
+ public CloudBlockBlob getBlockBlobReference(final String blobName) throws URISyntaxException, StorageException {
+ return this.getBlockBlobReference(blobName, null);
}
/**
@@ -868,6 +922,7 @@ public CloudBlockBlob getBlockBlobReference(final String blobName) throws URISyn
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
public CloudBlockBlob getBlockBlobReference(final String blobName, final String snapshotID)
throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("blobName", blobName);
@@ -945,15 +1000,11 @@ public StorageUri getStorageUri() {
* If the resource URI is invalid.
*/
public CloudPageBlob getPageBlobReference(final String blobName) throws URISyntaxException, StorageException {
- Utility.assertNotNullOrEmpty("blobName", blobName);
-
- final StorageUri address = PathUtility.appendPathToUri(this.storageUri, blobName);
-
- return new CloudPageBlob(address, this.blobServiceClient, this);
+ return this.getPageBlobReference(blobName, null);
}
/**
- * Returns a reference to a {@link CloudPageBlob} object that represents a page blob in the directory, using the
+ * Returns a reference to a {@link CloudPageBlob} object that represents a page blob in the container, using the
* specified snapshot ID.
*
* @param blobName
@@ -968,6 +1019,7 @@ public CloudPageBlob getPageBlobReference(final String blobName) throws URISynta
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
public CloudPageBlob getPageBlobReference(final String blobName, final String snapshotID)
throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("blobName", blobName);
@@ -1006,7 +1058,7 @@ private String getSharedAccessCanonicalName() {
String accountName = this.getServiceClient().getCredentials().getAccountName();
String containerName = this.getName();
- return String.format("/%s/%s", accountName, containerName);
+ return String.format("/%s/%s/%s", SR.BLOB, accountName, containerName);
}
/**
@@ -1095,7 +1147,7 @@ public Iterabletrue
if path-style URIs are used; otherwise, false
.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
* @throws StorageException
* If a storage service error occurred.
- * @throws URISyntaxException
- * If the resource URI is invalid.
*/
- private void parseQueryAndVerify(final StorageUri completeUri, final CloudBlobClient existingClient,
- final boolean usePathStyleUris) throws URISyntaxException, StorageException {
- Utility.assertNotNull("completeUri", completeUri);
+ private void parseQueryAndVerify(final StorageUri completeUri, final StorageCredentials credentials)
+ throws StorageException {
+ Utility.assertNotNull("completeUri", completeUri);
if (!completeUri.isAbsolute()) {
- final String errorMessage = String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString());
- throw new IllegalArgumentException(errorMessage);
+ throw new IllegalArgumentException(String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString()));
}
this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri);
+
+ final StorageCredentialsSharedAccessSignature parsedCredentials =
+ SharedAccessSignatureHelper.parseQuery(completeUri);
- final HashMapString
that represents the name being assigned to the container.
- */
- protected void setName(final String name) {
- this.name = name;
- }
-
/**
* Sets the list of URIs for all locations.
*
@@ -1553,7 +1577,7 @@ public void uploadMetadata(AccessCondition accessCondition, BlobRequestOptions o
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.uploadMetadataImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -1582,7 +1606,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlobContainer containe
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -1641,7 +1665,7 @@ public void uploadPermissions(final BlobContainerPermissions permissions, final
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
uploadPermissionsImpl(permissions, accessCondition, options), options.getRetryPolicyFactory(),
@@ -1670,7 +1694,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, aclBytes.length, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, aclBytes.length, context);
}
@Override
@@ -1704,6 +1728,19 @@ public Void preProcessResponse(CloudBlobContainer container, CloudBlobClient cli
}
}
+ /**
+ * Acquires a new infinite lease on the container.
+ *
+ * @return A String
that represents the lease ID.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final String acquireLease() throws StorageException {
+ return this.acquireLease(null /* leaseTimeInSeconds */, null /* proposedLeaseId */);
+ }
+
/**
* Acquires a new lease on the container with the specified lease time and proposed lease ID.
*
@@ -1768,7 +1805,7 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.acquireLeaseImpl(leaseTimeInSeconds, proposedLeaseId, accessCondition, options),
@@ -1792,7 +1829,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -1859,7 +1896,7 @@ public final void renewLease(final AccessCondition accessCondition, BlobRequestO
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this, this.renewLeaseImpl(accessCondition, options),
options.getRetryPolicyFactory(), opContext);
@@ -1881,7 +1918,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -1947,7 +1984,7 @@ public final void releaseLease(final AccessCondition accessCondition, BlobReques
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this, this.releaseLeaseImpl(accessCondition, options),
options.getRetryPolicyFactory(), opContext);
@@ -1968,7 +2005,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -2043,7 +2080,7 @@ public final long breakLease(final Integer breakPeriodInSeconds, final AccessCon
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.breakLeaseImpl(breakPeriodInSeconds, accessCondition, options), options.getRetryPolicyFactory(),
@@ -2065,7 +2102,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -2143,7 +2180,7 @@ public final String changeLease(final String proposedLeaseId, final AccessCondit
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.UNSPECIFIED, this.blobServiceClient);
return ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.changeLeaseImpl(proposedLeaseId, accessCondition, options), options.getRetryPolicyFactory(),
@@ -2165,7 +2202,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlobContainer
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobDirectory.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobDirectory.java
index 79b73898b04a1..c147bbbc1f4f4 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobDirectory.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlobDirectory.java
@@ -110,6 +110,52 @@ protected CloudBlobDirectory(final StorageUri uri, final String prefix, final Cl
this.storageUri = uri;
}
+ /**
+ * Returns a reference to a {@link CloudAppendBlob} object that represents an append blob in the directory.
+ *
+ * @param blobName
+ * A String
that represents the name of the blob.
+ *
+ * @return A {@link CloudAppendBlob} object that represents a reference to the specified append blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ * If the resource URI is invalid.
+ */
+ public CloudAppendBlob getAppendBlobReference(final String blobName) throws URISyntaxException, StorageException {
+ return this.getAppendBlobReference(blobName, null);
+ }
+
+ /**
+ * Returns a reference to a {@link CloudAppendBlob} object that represents an append blob in the directory, using the
+ * specified snapshot ID.
+ *
+ * @param blobName
+ * A String
that represents the name of the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot ID of the blob.
+ *
+ * @return A {@link CloudAppendBlob} object that represents a reference to the specified append blob.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ * If the resource URI is invalid.
+ */
+ public CloudAppendBlob getAppendBlobReference(final String blobName, final String snapshotID)
+ throws URISyntaxException, StorageException {
+ Utility.assertNotNullOrEmpty("blobName", blobName);
+
+ final StorageUri address = PathUtility.appendPathToUri(this.storageUri, blobName,
+ this.blobServiceClient.getDirectoryDelimiter());
+
+ final CloudAppendBlob retBlob = new CloudAppendBlob(address, snapshotID, this.blobServiceClient);
+ retBlob.setContainer(this.container);
+
+ return retBlob;
+ }
+
/**
* Returns a reference to a {@link CloudBlockBlob} object that represents a block blob in this directory.
*
@@ -143,6 +189,7 @@ public CloudBlockBlob getBlockBlobReference(final String blobName) throws URISyn
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
public CloudBlockBlob getBlockBlobReference(final String blobName, final String snapshotID)
throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("blobName", blobName);
@@ -176,7 +223,7 @@ public CloudBlobContainer getContainer() throws StorageException, URISyntaxExcep
* @param blobName
* A String
that represents the name of the blob.
*
- * @return A {@link CloudBlockBlob} object that represents a reference to the specified page blob.
+ * @return A {@link CloudPageBlob} object that represents a reference to the specified page blob.
*
* @throws StorageException
* If a storage service error occurred.
@@ -196,13 +243,14 @@ public CloudPageBlob getPageBlobReference(final String blobName) throws URISynta
* @param snapshotID
* A String
that represents the snapshot ID of the blob.
*
- * @return A {@link CloudBlockBlob} object that represents a reference to the specified page blob.
+ * @return A {@link CloudPageBlob} object that represents a reference to the specified page blob.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
public CloudPageBlob getPageBlobReference(final String blobName, final String snapshotID)
throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("blobName", blobName);
@@ -282,24 +330,6 @@ public CloudBlobDirectory getDirectoryReference(String directoryName) throws URI
return new CloudBlobDirectory(address, subDirName, this.blobServiceClient, this.container, this);
}
-
- /**
- * Returns a reference to a virtual blob directory beneath this directory.
- *
- * @param directoryName
- * A String
that represents the name of the virtual directory.
- *
- * @return A CloudBlobDirectory
object that represents a virtual blob directory beneath this directory.
- *
- * @throws URISyntaxException
- * If the resource URI is invalid.
- *
- * @deprecated as of 2.0.0. Use {@link #getDirectoryReference()} instead.
- */
- @Deprecated
- public CloudBlobDirectory getSubDirectoryReference(String directoryName) throws URISyntaxException {
- return this.getDirectoryReference(directoryName);
- }
/**
* Returns the URI for this directory.
@@ -471,7 +501,7 @@ public ResultSegmentCloudBlockBlob
class using the specified absolute URI and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlockBlob(final URI blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudBlockBlob
class using the specified absolute StorageUri and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute StorageUri to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlockBlob(final StorageUri blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(blobAbsoluteUri, null /* snapshotID */, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudBlockBlob
class using the specified absolute URI, snapshot ID, and
+ * credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlockBlob(final URI blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), snapshotID, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudBlockBlob
class using the specified absolute StorageUri, snapshot
+ * ID, and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute StorageUri to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudBlockBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ super(BlobType.BLOCK_BLOB, blobAbsoluteUri, snapshotID, credentials);
+ }
+
/**
* Creates an instance of the CloudBlockBlob
class using the specified absolute URI and storage service
* client.
@@ -96,7 +160,9 @@ public CloudBlockBlob(final CloudBlockBlob otherBlob) {
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final URI blobAbsoluteUri, final CloudBlobClient client) throws StorageException {
this(new StorageUri(blobAbsoluteUri), client);
}
@@ -112,7 +178,9 @@ public CloudBlockBlob(final URI blobAbsoluteUri, final CloudBlobClient client) t
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient client) throws StorageException {
super(BlobType.BLOCK_BLOB, blobAbsoluteUri, client);
}
@@ -130,7 +198,9 @@ public CloudBlockBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient cl
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final URI blobAbsoluteUri, final CloudBlobClient client, final CloudBlobContainer container)
throws StorageException {
this(new StorageUri(blobAbsoluteUri), client, container);
@@ -149,7 +219,9 @@ public CloudBlockBlob(final URI blobAbsoluteUri, final CloudBlobClient client, f
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient client,
final CloudBlobContainer container) throws StorageException {
super(BlobType.BLOCK_BLOB, blobAbsoluteUri, client, container);
@@ -168,7 +240,9 @@ public CloudBlockBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient cl
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(URI, String, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final URI blobAbsoluteUri, final String snapshotID, final CloudBlobClient client)
throws StorageException {
this(new StorageUri(blobAbsoluteUri), snapshotID, client);
@@ -187,11 +261,120 @@ public CloudBlockBlob(final URI blobAbsoluteUri, final String snapshotID, final
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudBlockBlob#CloudBlockBlob(StorageUri, String, StorageCredentials)}
*/
+ @Deprecated
public CloudBlockBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final CloudBlobClient client)
throws StorageException {
super(BlobType.BLOCK_BLOB, blobAbsoluteUri, snapshotID, client);
}
+
+ /**
+ * Requests the service to start copying a block blob's contents, properties, and metadata to a new block blob.
+ *
+ * @param sourceBlob
+ * A CloudBlockBlob
object that represents the source blob to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudBlockBlob sourceBlob) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceBlob, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a block blob's contents, properties, and metadata to a new block blob,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceBlob
+ * A CloudBlockBlob
object that represents the source blob to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source blob.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudBlockBlob sourceBlob, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceBlob", sourceBlob);
+ return this.startCopy(
+ sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
+
+ /**
+ * Requests the service to start copying a file's contents, properties, and metadata to a new block blob.
+ *
+ * @param sourceFile
+ * A CloudFile
object that represents the source file to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudFile sourceFile) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceFile, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a file's contents, properties, and metadata to a new block blob,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceFile
+ * A CloudFile
object that represents the source file to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source file.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination block blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ * If the resource URI is invalid.
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudFile sourceFile, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceFile", sourceFile);
+ return this.startCopy(
+ sourceFile.getServiceClient().getCredentials().transformUri(sourceFile.getUri()),
+ sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
/**
* Commits a block list to the storage service. In order to be written as part of a blob, a block must have been
@@ -240,7 +423,7 @@ public void commitBlockList(final IterableString
which represents the content that will be uploaded to the blob.
@@ -883,7 +1080,8 @@ public void uploadText(final String content) throws StorageException, IOExceptio
}
/**
- * Uploads a blob from a string using the specified encoding.
+ * Uploads a blob from a string using the specified encoding. If the blob already exists on the service, it will be
+ * overwritten.
*
* @param content
* A String
which represents the content that will be uploaded to the blob.
@@ -959,7 +1157,7 @@ public String downloadText(final String charsetName, final AccessCondition acces
/**
* Sets the number of bytes to buffer when writing to a {@link BlobOutputStream}.
*
- * @param writeBlockSizeInBytes
+ * @param streamWriteSizeInBytes
* An int
which represents the maximum block size, in bytes, for writing to a block blob
* while using a {@link BlobOutputStream} object, ranging from 16 KB to 4 MB, inclusive.
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java
index 5483c12b8eb52..ddf8596712c60 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudPageBlob.java
@@ -19,6 +19,7 @@
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
+import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -27,6 +28,7 @@
import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.DoesServiceRequest;
import com.microsoft.azure.storage.OperationContext;
+import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.StorageUri;
import com.microsoft.azure.storage.core.Base64;
@@ -65,12 +67,7 @@ public CloudPageBlob(final URI blobAbsoluteUri) throws StorageException {
* If a storage service error occurred.
*/
public CloudPageBlob(final StorageUri blobAbsoluteUri) throws StorageException {
- super(BlobType.PAGE_BLOB);
-
- Utility.assertNotNull("blobAbsoluteUri", blobAbsoluteUri);
- this.setStorageUri(blobAbsoluteUri);
- this.parseURIQueryStringAndVerify(blobAbsoluteUri, null,
- Utility.determinePathStyleFromUri(blobAbsoluteUri.getPrimaryUri()));;
+ this(blobAbsoluteUri, (StorageCredentials)null);
}
/**
@@ -82,6 +79,72 @@ public CloudPageBlob(final StorageUri blobAbsoluteUri) throws StorageException {
public CloudPageBlob(final CloudPageBlob otherBlob) {
super(otherBlob);
}
+
+ /**
+ * Creates an instance of the CloudPageBlob
class using the specified absolute URI and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudPageBlob(final URI blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudPageBlob
class using the specified absolute URI, snapshot ID, and
+ * credentials.
+ *
+ * @param blobAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudPageBlob(final URI blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ this(new StorageUri(blobAbsoluteUri), snapshotID, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudPageBlob
class using the specified absolute StorageUri and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the blob.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudPageBlob(final StorageUri blobAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(blobAbsoluteUri, null /* snapshotID */, credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudPageBlob
class using the specified absolute StorageUri, snapshot
+ * ID, and credentials.
+ *
+ * @param blobAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the blob.
+ * @param snapshotID
+ * A String
that represents the snapshot version, if applicable.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudPageBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final StorageCredentials credentials)
+ throws StorageException {
+ super(BlobType.PAGE_BLOB, blobAbsoluteUri, snapshotID, credentials);
+ }
/**
* Creates an instance of the CloudPageBlob
class using the specified URI and cloud blob client.
@@ -93,7 +156,9 @@ public CloudPageBlob(final CloudPageBlob otherBlob) {
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final URI blobAbsoluteUri, final CloudBlobClient client) throws StorageException {
this(new StorageUri(blobAbsoluteUri), client);
}
@@ -108,7 +173,9 @@ public CloudPageBlob(final URI blobAbsoluteUri, final CloudBlobClient client) th
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient client) throws StorageException {
super(BlobType.PAGE_BLOB, blobAbsoluteUri, client);
}
@@ -126,7 +193,9 @@ public CloudPageBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient cli
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final URI blobAbsoluteUri, final CloudBlobClient client, final CloudBlobContainer container)
throws StorageException {
this(new StorageUri(blobAbsoluteUri), client, container);
@@ -145,7 +214,9 @@ public CloudPageBlob(final URI blobAbsoluteUri, final CloudBlobClient client, fi
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient client,
final CloudBlobContainer container) throws StorageException {
super(BlobType.PAGE_BLOB, blobAbsoluteUri, client, container);
@@ -164,7 +235,9 @@ public CloudPageBlob(final StorageUri blobAbsoluteUri, final CloudBlobClient cli
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(URI, String, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final URI blobAbsoluteUri, final String snapshotID, final CloudBlobClient client)
throws StorageException {
this(new StorageUri(blobAbsoluteUri), snapshotID, client);
@@ -183,11 +256,66 @@ public CloudPageBlob(final URI blobAbsoluteUri, final String snapshotID, final C
*
* @throws StorageException
* If a storage service error occurred.
+ * @deprecated as of 3.0.0. Please use {@link CloudPageBlob#CloudPageBlob(StorageUri, String, StorageCredentials)}
*/
+ @Deprecated
public CloudPageBlob(final StorageUri blobAbsoluteUri, final String snapshotID, final CloudBlobClient client)
throws StorageException {
super(BlobType.PAGE_BLOB, blobAbsoluteUri, snapshotID, client);
}
+
+ /**
+ * Requests the service to start copying a blob's contents, properties, and metadata to a new blob.
+ *
+ * @param sourceBlob
+ * A CloudPageBlob
object that represents the source blob to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudPageBlob sourceBlob) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceBlob, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a blob's contents, properties, and metadata to a new blob, using the
+ * specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceBlob
+ * A CloudPageBlob
object that represents the source blob to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source blob.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination blob.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudPageBlob sourceBlob, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, BlobRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceBlob", sourceBlob);
+ return this.startCopy(
+ sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
/**
* Clears pages from a page blob.
@@ -249,15 +377,16 @@ public void clearPages(final long offset, final long length, final AccessConditi
opContext = new OperationContext();
}
- options = BlobRequestOptions.applyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
PageRange range = new PageRange(offset, offset + length - 1);
this.putPagesInternal(range, PageOperationType.CLEAR, null, length, null, accessCondition, options, opContext);
}
/**
- * Creates a page blob.
- *
+ * Creates a page blob. If the blob already exists, this will replace it. To instead throw an error if the blob
+ * already exists, use the {@link #create(long, AccessCondition, BlobRequestOptions, OperationContext)}
+ * overload with {@link AccessCondition#generateIfNotExistsCondition()}.
* @param length
* A long
which represents the size, in bytes, of the page blob.
*
@@ -272,7 +401,9 @@ public void create(final long length) throws StorageException {
}
/**
- * Creates a page blob using the specified request options and operation context.
+ * Creates a page blob using the specified request options and operation context. If the blob already exists,
+ * this will replace it. To instead throw an error if the blob already exists, use
+ * {@link AccessCondition#generateIfNotExistsCondition()}.
*
* @param length
* A long
which represents the size, in bytes, of the page blob.
@@ -306,7 +437,7 @@ public void create(final long length, final AccessCondition accessCondition, Blo
opContext = new OperationContext();
}
- options = BlobRequestOptions.applyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
this.createImpl(length, accessCondition, options), options.getRetryPolicyFactory(), opContext);
@@ -332,7 +463,7 @@ public void setHeaders(HttpURLConnection connection, CloudBlob blob, OperationCo
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -398,7 +529,7 @@ public ArrayListlong
which represents the length, in bytes, of the stream to create. This value must be
@@ -514,7 +650,11 @@ public BlobOutputStream openWriteNew(final long length) throws StorageException
/**
* Opens an output stream object to write data to the page blob, using the specified lease ID, request options and
- * operation context. The page blob does not need to yet exist and will be created with the length specified.
+ * operation context. The page blob does not need to yet exist and will be created with the length specified.If the
+ * blob already exists on the service, it will be overwritten.
+ * long
which represents the length, in bytes, of the stream to create. This value must be
@@ -574,7 +714,7 @@ private BlobOutputStream openOutputStreamInternal(Long length, AccessCondition a
assertNoWriteOperationForSnapshot();
- options = BlobRequestOptions.applyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient,
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient,
false /* setStartTime */);
if (options.getStoreBlobContentMD5()) {
@@ -667,10 +807,10 @@ public void setHeaders(HttpURLConnection connection, CloudPageBlob blob, Operati
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
if (operationType == PageOperationType.UPDATE) {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, length, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, length, context);
}
else {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
}
@@ -743,7 +883,7 @@ public void resize(long size, AccessCondition accessCondition, BlobRequestOption
}
opContext.initialize();
- options = BlobRequestOptions.applyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, this.properties.getBlobType(), this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this, this.resizeImpl(size, accessCondition, options),
options.getRetryPolicyFactory(), opContext);
@@ -764,7 +904,7 @@ public HttpURLConnection buildRequest(CloudBlobClient client, CloudPageBlob blob
@Override
public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, null);
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
}
@Override
@@ -786,10 +926,11 @@ public Void preProcessResponse(CloudPageBlob blob, CloudBlobClient client, Opera
}
/**
- * Uploads the source stream data to the page blob.
+ * Uploads the source stream data to the page blob. If the blob already exists on the service, it will be
+ * overwritten.
*
* @param sourceStream
- * An {@link IntputStream} object to read from.
+ * An {@link InputStream} object to read from.
* @param length
* A long
which represents the length, in bytes, of the stream data, must be non zero and a
* multiple of 512.
@@ -807,10 +948,10 @@ public void upload(final InputStream sourceStream, final long length) throws Sto
/**
* Uploads the source stream data to the page blob using the specified lease ID, request options, and operation
- * context.
+ * context. If the blob already exists on the service, it will be overwritten.
*
* @param sourceStream
- * An {@link IntputStream} object to read from.
+ * An {@link InputStream} object to read from.
* @param length
* A long
which represents the length, in bytes, of the stream data. This must be great than
* zero and a multiple of 512.
@@ -840,7 +981,7 @@ public void upload(final InputStream sourceStream, final long length, final Acce
opContext = new OperationContext();
}
- options = BlobRequestOptions.applyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
if (length <= 0 || length % Constants.PAGE_SIZE != 0) {
throw new IllegalArgumentException(SR.INVALID_PAGE_BLOB_LENGTH);
@@ -868,7 +1009,7 @@ public void upload(final InputStream sourceStream, final long length, final Acce
* Uploads a range of contiguous pages, up to 4 MB in size, at the specified offset in the page blob.
*
* @param sourceStream
- * An {@link IntputStream} object which represents the input stream to write to the page blob.
+ * An {@link InputStream} object which represents the input stream to write to the page blob.
* @param offset
* A long
which represents the offset, in number of bytes, at which to begin writing the
* data. This value must be a multiple of 512.
@@ -894,7 +1035,7 @@ public void uploadPages(final InputStream sourceStream, final long offset, final
* specified lease ID, request options, and operation context.
*
* @param sourceStream
- * An {@link IntputStream} object which represents the input stream to write to the page blob.
+ * An {@link InputStream} object which represents the input stream to write to the page blob.
* @param offset
* A long
which represents the offset, in number of bytes, at which to begin writing the
* data. This value must be a multiple of
@@ -943,7 +1084,7 @@ public void uploadPages(final InputStream sourceStream, final long offset, final
opContext = new OperationContext();
}
- options = BlobRequestOptions.applyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
final PageRange pageRange = new PageRange(offset, offset + length - 1);
final byte[] data = new byte[(int) length];
@@ -975,7 +1116,7 @@ public void uploadPages(final InputStream sourceStream, final long offset, final
/**
* Sets the number of bytes to buffer when writing to a {@link BlobOutputStream}.
*
- * @param pageBlobStreamWriteSizeInBytes
+ * @param streamWriteSizeInBytes
* An int
which represents the maximum number of bytes to buffer when writing to a page blob
* stream. This value must be a
* multiple of 512 and
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java
index 87d9c9ba78598..99210e226068e 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyState.java
@@ -22,7 +22,7 @@
*/
public final class CopyState {
/**
- * Holds the name of the container.
+ * Holds the ID for the copy operation.
*/
private String copyId;
@@ -58,15 +58,9 @@ public final class CopyState {
private String statusDescription;
/**
- * Initializes a new instance of the CopyState class.
- */
- public CopyState() {
- }
-
- /**
- * Gets the copy ID of the container.
+ * Gets the ID of the copy operation.
*
- * @return A String
which represents the copy ID of the container.
+ * @return A String
which represents the ID of the copy operation.
*/
public String getCopyId() {
return this.copyId;
@@ -93,7 +87,7 @@ public CopyStatus getStatus() {
/**
* Gets the source URI of the copy operation.
*
- * @return A {@link java.net.URI} objeect which represents the source URI of the copy operation in a string.
+ * @return A {@link java.net.URI} object which represents the source URI of the copy operation in a string.
*/
public URI getSource() {
return this.source;
@@ -111,7 +105,7 @@ public Long getBytesCopied() {
/**
* Gets the number of bytes total number of bytes to copy.
*
- * @returnA long
which represents the total number of bytes to copy/
+ * @return A long
which represents the total number of bytes to copy/
*/
public Long getTotalBytes() {
return this.totalBytes;
@@ -127,13 +121,13 @@ public String getStatusDescription() {
}
/**
- * Sets the copy ID of the container.
+ * Sets the ID of the copy operation.
*
* @param copyId
- * A String
which specifies the copy ID of the container to set.
+ * A String
which specifies the ID of the copy operation to set.
*
*/
- protected void setCopyId(final String copyId) {
+ void setCopyId(final String copyId) {
this.copyId = copyId;
}
@@ -143,7 +137,7 @@ protected void setCopyId(final String copyId) {
* @param completionTime
* A {@link java.util.Date} object which specifies the time when the copy operation completed.
*/
- protected void setCompletionTime(final Date completionTime) {
+ void setCompletionTime(final Date completionTime) {
this.completionTime = completionTime;
}
@@ -153,7 +147,7 @@ protected void setCompletionTime(final Date completionTime) {
* @param status
* A {@link CopyStatus}
object specifies the status of the copy operation.
*/
- protected void setStatus(final CopyStatus status) {
+ void setStatus(final CopyStatus status) {
this.status = status;
}
@@ -163,7 +157,7 @@ protected void setStatus(final CopyStatus status) {
* @param source
* A {@link java.net.URI} object which specifies the source URI.
*/
- protected void setSource(final URI source) {
+ void setSource(final URI source) {
this.source = source;
}
@@ -173,7 +167,7 @@ protected void setSource(final URI source) {
* @param bytesCopied
* A long
which specifies the number of bytes copied.
*/
- protected void setBytesCopied(final Long bytesCopied) {
+ void setBytesCopied(final Long bytesCopied) {
this.bytesCopied = bytesCopied;
}
@@ -183,7 +177,7 @@ protected void setBytesCopied(final Long bytesCopied) {
* @param totalBytes
* A long
which specifies the number of bytes to copy.
*/
- protected void setTotalBytes(final Long totalBytes) {
+ void setTotalBytes(final Long totalBytes) {
this.totalBytes = totalBytes;
}
@@ -193,7 +187,6 @@ protected void setTotalBytes(final Long totalBytes) {
* @param statusDescription
* A String
which specifies the status description.
*/
- protected void setStatusDescription(final String statusDescription) {
+ void setStatusDescription(final String statusDescription) {
this.statusDescription = statusDescription;
- }
-}
+ }}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyStatus.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyStatus.java
index dc29a799f6660..6ab1b6cc7e89a 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyStatus.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CopyStatus.java
@@ -60,7 +60,7 @@ public enum CopyStatus {
*
* @return A CopyStatus
value that represents the copy status.
*/
- protected static CopyStatus parse(final String typeString) {
+ static CopyStatus parse(final String typeString) {
if (Utility.isNullOrEmpty(typeString)) {
return UNSPECIFIED;
}
@@ -83,4 +83,4 @@ else if ("failed".equals(typeString.toLowerCase(Locale.US))) {
return UNSPECIFIED;
}
}
-}
+}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobHeaders.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobHeaders.java
index 134ef5caadc2f..a23ab851003f1 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobHeaders.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobHeaders.java
@@ -14,153 +14,25 @@
*/
package com.microsoft.azure.storage.blob;
-import com.microsoft.azure.storage.core.Utility;
+import com.microsoft.azure.storage.SharedAccessHeaders;
/**
* Represents the optional headers that can be returned with blobs accessed using SAS.
*/
-public final class SharedAccessBlobHeaders {
-
- /**
- * The cache-control header returned with the blob.
- */
- private String cacheControl;
-
- /**
- * The content-disposition header returned with the blob.
- */
- private String contentDisposition;
-
- /**
- * The content-encoding header returned with the blob.
- */
- private String contentEncoding;
-
- /**
- * The content-language header returned with the blob.
- */
- private String contentLanguage;
-
- /**
- * The content-type header returned with the blob.
- */
- private String contentType;
-
+public final class SharedAccessBlobHeaders extends SharedAccessHeaders {
/**
* Initializes a new instance of the {@link SharedAccessBlobHeaders} class.
*/
public SharedAccessBlobHeaders() {
-
}
/**
* Initializes a new instance of the {@link SharedAccessBlobHeaders} class based on an existing instance.
*
* @param other
- * A {@link SharedAccessBlobHeaders} object which specifies the set of blob properties to clone.
- */
- public SharedAccessBlobHeaders(SharedAccessBlobHeaders other) {
- Utility.assertNotNull("other", other);
-
- this.contentType = other.contentType;
- this.contentDisposition = other.contentDisposition;
- this.contentEncoding = other.contentEncoding;
- this.contentLanguage = other.contentLanguage;
- this.cacheControl = other.cacheControl;
- }
-
- /**
- * Gets the cache control header.
- *
- * @return A String
which represents the cache control header.
- */
- public final String getCacheControl() {
- return this.cacheControl;
- }
-
- /**
- * Sets the cache control header.
- *
- * @param cacheControl
- * A String
which specifies the cache control header.
- */
- public void setCacheControl(String cacheControl) {
- this.cacheControl = cacheControl;
- }
-
- /**
- * Gets the content disposition header.
- *
- * @return A String
which represents the content disposition header.
- */
- public final String getContentDisposition() {
- return this.contentDisposition;
- }
-
- /**
- * Sets the content disposition header.
- *
- * @param contentDisposition
- * A String
which specifies the content disposition header.
- */
- public void setContentDisposition(String contentDisposition) {
- this.contentDisposition = contentDisposition;
- }
-
- /**
- * Gets the content encoding header.
- *
- * @return A String
which represents the content encoding header.
- */
- public final String getContentEncoding() {
- return this.contentEncoding;
- }
-
- /**
- * Sets the content encoding header.
- *
- * @param contentEncoding
- * A String
which specifies the content encoding header.
- */
- public void setContentEncoding(String contentEncoding) {
- this.contentEncoding = contentEncoding;
- }
-
- /**
- * Gets the content language header.
- *
- * @return A String
which represents the content language header.
- */
- public final String getContentLanguage() {
- return this.contentLanguage;
- }
-
- /**
- * Sets the content language header.
- *
- * @param contentLanguage
- * A String
which specifies the content language header.
- */
- public void setContentLanguage(String contentLanguage) {
- this.contentLanguage = contentLanguage;
- }
-
- /**
- * Gets the content type header.
- *
- * @return A String
which represents the content type header.
- */
- public final String getContentType() {
- return this.contentType;
- }
-
- /**
- * Sets the content type header.
- *
- * @param contentType
- * A String
which specifies the content type header.
+ * A {@link SharedAccessHeaders} object which specifies the set of properties to clone.
*/
- public void setContentType(String contentType) {
- this.contentType = contentType;
+ public SharedAccessBlobHeaders(SharedAccessHeaders other) {
+ super(other);
}
-}
+}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPermissions.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPermissions.java
index 61e3da2a3158b..d9d46a05ee937 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPermissions.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPermissions.java
@@ -14,8 +14,6 @@
*/
package com.microsoft.azure.storage.blob;
-import java.util.EnumSet;
-
/**
* Specifies the set of possible permissions for a shared access policy.
*/
@@ -23,63 +21,20 @@ public enum SharedAccessBlobPermissions {
/**
* Specifies Read access granted.
*/
- READ((byte) 0x1),
+ READ,
/**
* Specifies Write access granted.
*/
- WRITE((byte) 0x2),
+ WRITE,
/**
* Specifies Delete access granted for blobs.
*/
- DELETE((byte) 0x4),
+ DELETE,
/**
* Specifies List access granted.
*/
- LIST((byte) 0x8);
-
- /**
- * Returns the enum set representing the shared access permissions for the specified byte value.
- *
- * @param value
- * The byte value to convert to the corresponding enum set.
- * @return A java.util.EnumSet
object that contains the SharedAccessBlobPermissions
values
- * corresponding to the specified byte value.
- */
- protected static EnumSetbyte
which specifies the value being assigned.
- */
- private SharedAccessBlobPermissions(final byte val) {
- this.value = val;
- }
-}
+ LIST;
+}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPolicy.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPolicy.java
index 10d2b305ce988..d1ecfa0c85454 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPolicy.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobPolicy.java
@@ -18,6 +18,7 @@
import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.SharedAccessPolicy;
+import com.microsoft.azure.storage.blob.SharedAccessBlobPermissions;
/**
* Represents a shared access policy, which specifies the start time, expiry time, and permissions for a shared access
@@ -28,7 +29,7 @@ public final class SharedAccessBlobPolicy extends SharedAccessPolicy {
* The permissions for a shared access signature associated with this shared access policy.
*/
private EnumSetString
that represents the shared access permissions in the "rwdl" format, which is
- * described at {@link SharedAccessBlobPolicy#permissionsFromString(String)}.
+ * @return A String
that represents the shared access permissions in the "rwdl" format,
+ * which is described at {@link #setPermissionsFromString(String)}.
*/
@Override
public String permissionsToString() {
@@ -98,30 +99,27 @@ public String permissionsToString() {
* w
: Write access.True
if a request can be signed with these
- // credentials; otherwise, false
- //
- /** Reserved. */
- public static boolean canCredentialsSignRequest(final StorageCredentials creds) {
- if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
- return true;
- }
- else {
- return false;
- }
- }
-
- //
- // RESERVED, for internal use only. Gets a value indicating whether a
- // request can be signed under the Shared Key Lite authentication scheme
- // using the specified credentials.
- //
- // @return true
if a request can be signed with these
- // credentials; otherwise, false
- //
- /**
- * Reserved.
- *
- * @deprecated as of 2.0.0. Use {@link #canCredentialsSignRequest} instead.
+ /**
+ * RESERVED, for internal use only. Gets a value indicating whether a
+ * request can be signed under the Shared Key authentication scheme using
+ * the specified credentials.
+
+ * @return true
if a request can be signed with these
+ * credentials; otherwise, false
*/
- @Deprecated
- public static boolean canCredentialsSignRequestLite(final StorageCredentials creds) {
+ public static boolean canCredentialsSignRequest(final StorageCredentials creds) {
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
return true;
}
@@ -80,27 +57,6 @@ public static boolean canCredentialsSignRequestLite(final StorageCredentials cre
* If the key is not a valid Base64-encoded string.
*/
public static String computeHmac256(final StorageCredentials creds, final String value) throws InvalidKeyException {
- return computeHmac256(creds, value, null);
- }
-
- /**
- * Computes a signature for the specified string using the HMAC-SHA256 algorithm with the specified operation
- * context.
- *
- * @param value
- * The UTF-8-encoded string to sign.
- * @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 String
that contains the HMAC-SHA256-encoded signature.
- *
- * @throws InvalidKeyException
- * If the key is not a valid Base64-encoded string.
- */
- public static String computeHmac256(final StorageCredentials creds, final String value,
- final OperationContext opContext) throws InvalidKeyException {
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
return StorageKey.computeMacSha256(((StorageCredentialsAccountAndKey) creds).getCredentials().getKey(),
value);
@@ -126,7 +82,7 @@ public static String computeHmac256(final StorageCredentials creds, final String
public static void signBlobAndQueueRequest(final StorageCredentials creds,
final java.net.HttpURLConnection request, final long contentLength) throws InvalidKeyException,
StorageException {
- signBlobAndQueueRequest(creds, request, contentLength, null);
+ signBlobQueueAndFileRequest(creds, request, contentLength, null);
}
/**
@@ -146,65 +102,14 @@ public static void signBlobAndQueueRequest(final StorageCredentials creds,
* @throws StorageException
* If a storage service error occurred.
*/
- public static void signBlobAndQueueRequest(final StorageCredentials creds,
+ public static void signBlobQueueAndFileRequest(final StorageCredentials creds,
final java.net.HttpURLConnection request, final long contentLength, OperationContext opContext)
throws InvalidKeyException, StorageException {
+
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
opContext = opContext == null ? new OperationContext() : opContext;
- BaseRequest.signRequestForBlobAndQueue(request, ((StorageCredentialsAccountAndKey) creds).getCredentials(),
- contentLength, opContext);
- }
- }
-
- /**
- * Signs a request using the Shared Key Lite authentication scheme.
- *
- * @param request
- * An HttpURLConnection
object that represents the request to sign.
- * @param contentLength
- * The length of the content written to the output stream. If unknown, specify -1.
- *
- * @throws InvalidKeyException
- * If the given key is invalid.
- * @throws StorageException
- * If an unspecified storage exception occurs.
- *
- * @deprecated as of 2.0.0. Use {@link #signBlobAndQueueRequest} instead.
- */
- @Deprecated
- public static void signBlobAndQueueRequestLite(final StorageCredentials creds,
- final java.net.HttpURLConnection request, final long contentLength) throws InvalidKeyException,
- StorageException {
- signBlobAndQueueRequestLite(creds, request, contentLength, null);
- }
-
- /**
- * Signs a request using the specified operation context under the Shared Key Lite authentication scheme.
- *
- * @param request
- * An HttpURLConnection
object that represents the request to sign.
- * @param contentLength
- * The length of the content written to the output stream. If unknown, specify -1.
- * @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.
- *
- * @throws InvalidKeyException
- * If the given key is invalid.
- * @throws StorageException
- * If a storage service error occurred.
- *
- * @deprecated as of 2.0.0. Use {@link #signBlobAndQueueRequest} instead.
- */
- @Deprecated
- public static void signBlobAndQueueRequestLite(final StorageCredentials creds,
- final java.net.HttpURLConnection request, final long contentLength, OperationContext opContext)
- throws StorageException, InvalidKeyException {
- if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
- opContext = opContext == null ? new OperationContext() : opContext;
- BaseRequest.signRequestForBlobAndQueueSharedKeyLite(request,
- ((StorageCredentialsAccountAndKey) creds).getCredentials(), contentLength, opContext);
+ BaseRequest.signRequestForBlobAndQueue(
+ request, (StorageCredentialsAccountAndKey) creds, contentLength, opContext);
}
}
@@ -248,57 +153,14 @@ public static void signTableRequest(final StorageCredentials creds, final java.n
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
opContext = opContext == null ? new OperationContext() : opContext;
BaseRequest.signRequestForTableSharedKey(request,
- ((StorageCredentialsAccountAndKey) creds).getCredentials(), contentLength, opContext);
+ (StorageCredentialsAccountAndKey) creds, contentLength, opContext);
}
}
-
+
/**
- * Signs a request using the Shared Key Lite authentication scheme.
- *
- * @param request
- * An HttpURLConnection
object that represents the request to sign.
- * @param contentLength
- * The length of the content written to the output stream. If unknown, specify -1.
- *
- * @throws InvalidKeyException
- * If the given key is invalid.
- * @throws StorageException
- * If an unspecified storage exception occurs.
- *
- * @deprecated as of 2.0.0. Use {@link #signTableRequest} instead.
- */
- @Deprecated
- public static void signTableRequestLite(final StorageCredentials creds, final java.net.HttpURLConnection request,
- final long contentLength) throws InvalidKeyException, StorageException {
- signTableRequestLite(creds, request, contentLength, null);
- }
-
- /**
- * Signs a request using the specified operation context under the Shared Key Lite authentication scheme.
- *
- * @param request
- * An HttpURLConnection
object that represents the request to sign.
- * @param contentLength
- * The length of the content written to the output stream. If unknown, specify -1.
- * @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.
- *
- * @throws InvalidKeyException
- * If the given key is invalid.
- * @throws StorageException
- * If a storage service error occurred.
- *
- * @deprecated as of 2.0.0. Use {@link #signTableRequest} instead.
+ * A private default constructor. All methods of this class are static so no instances of it should ever be created.
*/
- @Deprecated
- public static void signTableRequestLite(final StorageCredentials creds, final java.net.HttpURLConnection request,
- final long contentLength, OperationContext opContext) throws StorageException, InvalidKeyException {
- if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
- opContext = opContext == null ? new OperationContext() : opContext;
- BaseRequest.signRequestForTableSharedKeyLite(request,
- ((StorageCredentialsAccountAndKey) creds).getCredentials(), contentLength, opContext);
- }
+ private StorageCredentialsHelper() {
+ //No op
}
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/StorageRequest.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/StorageRequest.java
index 7d94f451e77bc..09d6ff42e3fb3 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/StorageRequest.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/StorageRequest.java
@@ -21,7 +21,6 @@
import java.security.InvalidKeyException;
import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.AuthenticationScheme;
import com.microsoft.azure.storage.LocationMode;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.RequestOptions;
@@ -42,7 +41,6 @@
* @param CloudFile
class using the specified absolute URI.
+ *
+ * @param fileAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the file.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudFile(final URI fileAbsoluteUri) throws StorageException {
+ this(new StorageUri(fileAbsoluteUri));
+ }
+
+ /**
+ * Creates an instance of the CloudFile
class using the specified absolute StorageUri.
+ *
+ * @param fileAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the file.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudFile(final StorageUri fileAbsoluteUri) throws StorageException {
+ this(fileAbsoluteUri, (StorageCredentials)null);
+ }
+
+ /**
+ * Creates an instance of the CloudFile
class using the specified absolute URI
+ * and credentials.
+ *
+ * @param fileAbsoluteUri
+ * A java.net.URI
object that represents the absolute URI to the file.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudFile(final URI fileAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this(new StorageUri(fileAbsoluteUri), credentials);
+ }
+
+ /**
+ * Creates an instance of the CloudFile
class using the specified absolute StorageUri
+ * and credentials.
+ *
+ * @param fileAbsoluteUri
+ * A {@link StorageUri} object that represents the absolute URI to the file.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public CloudFile(final StorageUri fileAbsoluteUri, final StorageCredentials credentials) throws StorageException {
+ this.parseQueryAndVerify(fileAbsoluteUri, credentials);
+ }
+
/**
* Creates an instance of the CloudFile
class using the specified absolute URI and storage service
* client.
@@ -110,12 +176,14 @@ public class CloudFile implements ListFileItem {
* @param fileAbsoluteUri
* A java.net.URI
object that represents the absolute URI to the file.
* @param client
- * A {@link CloudFileClient} object that specifies the endpoint for the File service.
+ * A {@link CloudFileClient} object that specifies the endpoint for the file service.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFile#CloudFile(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudFile(final URI fileAbsoluteUri, final CloudFileClient client) throws StorageException,
URISyntaxException {
this(new StorageUri(fileAbsoluteUri), client);
@@ -127,26 +195,22 @@ public CloudFile(final URI fileAbsoluteUri, final CloudFileClient client) throws
* @param fileAbsoluteUri
* A {@link StorageUri} object that represents the absolute URI to the file.
* @param client
- * A {@link CloudFileClient} object that specifies the endpoint for the File service.
+ * A {@link CloudFileClient} object that specifies the endpoint for the file service.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFile#CloudFile(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudFile(final StorageUri fileAbsoluteUri, final CloudFileClient client) throws StorageException,
URISyntaxException {
- Utility.assertNotNull("fileAbsoluteUri", fileAbsoluteUri);
-
- this.metadata = new HashMapjava.net.URI
object that represents the absolute URI to the file.
* @param client
- * A {@link CloudFileClient} object that specifies the endpoint for the File service.
+ * A {@link CloudFileClient} object that specifies the endpoint for the file service.
* @param share
* A {@link CloudFileShare} object that represents the share to use for the file.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFile#CloudFile(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudFile(final URI fileAbsoluteUri, final CloudFileClient client, final CloudFileShare share)
throws StorageException, URISyntaxException {
this(new StorageUri(fileAbsoluteUri), client, share);
@@ -176,14 +242,16 @@ public CloudFile(final URI fileAbsoluteUri, final CloudFileClient client, final
* @param fileAbsoluteUri
* A {@link StorageUri} object that represents the absolute URI to the file.
* @param client
- * A {@link CloudFileClient} object that specifies the endpoint for the File service.
+ * A {@link CloudFileClient} object that specifies the endpoint for the file service.
* @param share
* A {@link CloudFileShare} object that represents the share to use for the file.
*
* @throws StorageException
* If a storage service error occurred.
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFile#CloudFile(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudFile(final StorageUri fileAbsoluteUri, final CloudFileClient client, final CloudFileShare share)
throws StorageException, URISyntaxException {
this(fileAbsoluteUri, client);
@@ -214,6 +282,300 @@ public CloudFile(final CloudFile otherFile) {
this.setStreamWriteSizeInBytes(otherFile.getStreamWriteSizeInBytes());
}
+ /**
+ * Aborts an ongoing Azure File copy operation.
+ *
+ * @param copyId
+ * A String
object that identifies the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final void abortCopy(final String copyId) throws StorageException {
+ this.abortCopy(copyId, null /* accessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Aborts an ongoing Azure File copy operation.
+ *
+ * @param copyId
+ * A String
object that identifies the copy operation.
+ * @param accessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the Azure File.
+ * @param options
+ * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client (
+ * {@link CloudFileClient}).
+ * @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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final void abortCopy(final String copyId, final AccessCondition accessCondition, FileRequestOptions options,
+ OperationContext opContext) throws StorageException {
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ opContext.initialize();
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
+
+ ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
+ this.abortCopyImpl(copyId, accessCondition, options), options.getRetryPolicyFactory(), opContext);
+ }
+
+ private StorageRequestCloudBlob
object that represents the source blob to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudBlob sourceBlob) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceBlob, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a file's contents, properties, and metadata to a new file,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceBlob
+ * A CloudBlob
object that represents the source blob to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source blob.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination file.
+ * @param options
+ * A {@link BlobRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudBlob sourceBlob, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceBlob", sourceBlob);
+ return this.startCopy(
+ sourceBlob.getQualifiedUri(), sourceAccessCondition, destinationAccessCondition, options, opContext);
+ }
+
+ /**
+ * Requests the service to start copying an Azure File's contents, properties, and metadata to a new Azure File.
+ *
+ * @param sourceFile
+ * A CloudFile
object that represents the source Azure File to copy.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudFile sourceFile) throws StorageException, URISyntaxException {
+ return this.startCopy(sourceFile, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying an Azure File's contents, properties, and metadata to a new Azure File,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param sourceFile
+ * A CloudFile
object that represents the source file to copy.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination.
+ * @param options
+ * A {@link FileRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
will use the default request options from the associated
+ * service client ({@link CloudFileClient}).
+ * @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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ * @throws URISyntaxException
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final CloudFile sourceFile, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
+ throws StorageException, URISyntaxException {
+ Utility.assertNotNull("sourceFile", sourceFile);
+ return this.startCopy(sourceFile.getTransformedAddress(opContext).getPrimaryUri(),
+ sourceAccessCondition, destinationAccessCondition, options, opContext);
+
+ }
+
+ /**
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new Azure File.
+ *
+ * @param source
+ * The source's java.net.URI
.
+ *
+ * @return A String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final String startCopy(final URI source) throws StorageException {
+ return this.startCopy(source, null /* sourceAccessCondition */,
+ null /* destinationAccessCondition */, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Requests the service to start copying a URI's contents, properties, and metadata to a new Azure File,
+ * using the specified access conditions, lease ID, request options, and operation context.
+ *
+ * @param source
+ * The source's java.net.URI
.
+ * @param sourceAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the source.
+ * @param destinationAccessCondition
+ * An {@link AccessCondition} object that represents the access conditions for the destination.
+ * @param options
+ * A {@link FileRequestOptions} object that specifies any additional options for the request.
+ * Specifying null
will use the default request options from the associated
+ * service client ({@link CloudFileClient}).
+ * @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 String
which represents the copy ID associated with the copy operation.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ *
+ */
+ @DoesServiceRequest
+ public final String startCopy(final URI source, final AccessCondition sourceAccessCondition,
+ final AccessCondition destinationAccessCondition, FileRequestOptions options, OperationContext opContext)
+ throws StorageException {
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ opContext.initialize();
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
+
+ return ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
+ this.startCopyImpl(source, sourceAccessCondition, destinationAccessCondition, options),
+ options.getRetryPolicyFactory(), opContext);
+ }
+
+ private StorageRequestlong
which represents the size, in bytes, of the file.
@@ -287,7 +649,8 @@ public void create(final long size) throws StorageException {
}
/**
- * Creates a file using the specified access condition, request options and operation context.
+ * Creates a file using the specified access condition, request options and operation context. If the file already
+ * exists, this will replace it.
*
* @param size
* A long
which represents the size, in bytes, of the file.
@@ -313,7 +676,7 @@ public void create(final long size, final AccessCondition accessCondition, FileR
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
ExecutionEngine.executeWithRetry(this.fileServiceClient, this, this.createImpl(size, accessCondition, options),
options.getRetryPolicyFactory(), opContext);
@@ -321,8 +684,8 @@ public void create(final long size, final AccessCondition accessCondition, FileR
private StorageRequestLong
which represents the number of bytes to read or null.
* @param buffer
* A byte
array which represents the buffer to which the file bytes are downloaded.
- * @param bufferOffet
+ * @param bufferOffset
* An int
which represents the byte offset to use as the starting point for the target.
*
* @throws StorageException
*/
@DoesServiceRequest
public final int downloadRangeToByteArray(final long offset, final Long length, final byte[] buffer,
- final int bufferOffet) throws StorageException {
- return this.downloadRangeToByteArray(offset, length, buffer, bufferOffet, null /* accessCondition */,
+ final int bufferOffset) throws StorageException {
+ return this.downloadRangeToByteArray(offset, length, buffer, bufferOffset, null /* accessCondition */,
null /* options */, null /* opContext */);
}
@@ -714,16 +1077,16 @@ public final int downloadRangeToByteArray(final long offset, final Long length,
*
* @param buffer
* A byte
array which represents the buffer to which the file bytes are downloaded.
- * @param bufferOffet
+ * @param bufferOffset
* An int
which represents the byte offset to use as the starting point for the target.
*
* @throws StorageException
* If a storage service error occurred.
*/
@DoesServiceRequest
- public final int downloadToByteArray(final byte[] buffer, final int bufferOffet) throws StorageException {
+ public final int downloadToByteArray(final byte[] buffer, final int bufferOffset) throws StorageException {
return this
- .downloadToByteArray(buffer, bufferOffet, null /* accessCondition */, null /* options */, null /* opContext */);
+ .downloadToByteArray(buffer, bufferOffset, null /* accessCondition */, null /* options */, null /* opContext */);
}
/**
@@ -732,7 +1095,7 @@ public final int downloadToByteArray(final byte[] buffer, final int bufferOffet)
*
* @param buffer
* A byte
array which represents the buffer to which the file bytes are downloaded.
- * @param bufferOffet
+ * @param bufferOffset
* A long
which represents the byte offset to use as the starting point for the target.
* @param accessCondition
* An {@link AccessCondition} object that represents the access conditions for the file.
@@ -767,7 +1130,7 @@ public final int downloadToByteArray(final byte[] buffer, final int bufferOffset
}
opContext.initialize();
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
return ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
this.downloadToByteArrayImpl(null, null, buffer, bufferOffset, accessCondition, options, opContext),
@@ -919,8 +1282,8 @@ public ArrayListArrayList
object which represents the set of file ranges and their starting and ending
- * byte offsets.
+ * @return An ArrayList
object which represents the set of file ranges and their starting
+ * and ending byte offsets.
*
* @throws StorageException
* If a storage service error occurred.
@@ -932,7 +1295,7 @@ public ArrayList{@link SharedAccessFilePolicy}
object that represents the access policy for the shared
+ * access signature.
+ * @param groupPolicyIdentifier
+ * A String
that represents the share-level access policy.
+ *
+ * @return A String
that represents the shared access signature.
+ *
+ * @throws InvalidKeyException
+ * If the credentials are invalid.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public String generateSharedAccessSignature(final SharedAccessFilePolicy policy, final String groupPolicyIdentifier)
+ throws InvalidKeyException, StorageException {
+ return generateSharedAccessSignature(policy, null /* headers */, groupPolicyIdentifier);
+ }
+
+ /**
+ * Returns a shared access signature for the file using the specified group policy identifier and
+ * shared access file headers. Note this does not contain the leading "?".
+ *
+ * @param policy
+ * A {@link SharedAccessFilePolicy}
object that represents the access policy for the shared
+ * access signature.
+ * @param headers
+ * A {@link SharedAccessFileHeaders}
object that represents the optional header values to
+ * set for a file accessed with this shared access signature.
+ * @param groupPolicyIdentifier
+ * A String
that represents the share-level access policy.
+ *
+ * @return A String
that represents the shared access signature.
+ *
+ * @throws IllegalArgumentException
+ * If the credentials are invalid.
+ * @throws InvalidKeyException
+ * If the credentials are invalid.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ public String generateSharedAccessSignature(final SharedAccessFilePolicy policy,
+ final SharedAccessFileHeaders headers, final String groupPolicyIdentifier)
+ throws InvalidKeyException, StorageException {
+ if (!StorageCredentialsHelper.canCredentialsSignRequest(this.fileServiceClient.getCredentials())) {
+ throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
+ }
+
+ final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile(
+ policy, headers, groupPolicyIdentifier, this.getCanonicalName(), this.fileServiceClient);
+
+ final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile(
+ policy, headers, groupPolicyIdentifier, "f", signature);
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns the canonical name of the file in the format of
+ * /<service-name>/<account-name>/<share-name>/<file-name>.
+ * InputStream
object that represents the stream to use for reading from the file.
*
@@ -1499,9 +1958,10 @@ public final FileInputStream openRead() throws StorageException {
}
/**
- * Opens a file input stream to download the file using the specified request options and operation context.
+ * Opens a file input stream to download the file using the specified request options and
+ * operation context.
* InputStream
object that represents the stream to use for reading from the File.
+ * @return An InputStream
object that represents the stream to use for reading from the file.
*
* @throws StorageException
* If a storage service error occurred.
@@ -1526,13 +1986,14 @@ public final FileInputStream openRead(final AccessCondition accessCondition, Fil
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient, false /* setStartTime */);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient, false /* setStartTime */);
return new FileInputStream(this, accessCondition, options, opContext);
}
/**
- * Opens an output stream object to write data to the file. The file must already exist.
+ * Opens an output stream object to write data to the file. The file must already exist and any existing data may
+ * be overwritten.
*
* @return A {@link FileOutputStream} object used to write data to the file.
*
@@ -1547,7 +2008,7 @@ public FileOutputStream openWriteExisting() throws StorageException {
/**
* Opens an output stream object to write data to the file, using specified request options and
- * operation context. The file must already exist.
+ * operation context. The file must already exist and any existing data may be overwritten.
*
* @param accessCondition
* An {@link AccessCondition} object which represents the access conditions for the file.
@@ -1574,7 +2035,11 @@ public FileOutputStream openWriteExisting(AccessCondition accessCondition, FileR
/**
* Opens an output stream object to write data to the file. The file does not yet exist and will
- * be created with the length specified.
+ * be created with the length specified. If the file already exists on the service, it will be overwritten.
+ * long
which represents the length, in bytes, of the stream to create.
@@ -1592,7 +2057,11 @@ public FileOutputStream openWriteNew(final long length) throws StorageException
/**
* Opens an output stream object to write data to the file, using the specified lease ID, request options and
- * operation context. The file does not need to yet exist and will be created with the length specified.
+ * operation context. The file does not need to yet exist and will be created with the length specified. If the file
+ * already exists on the service, it will be overwritten.
+ * long
which represents the length, in bytes, of the stream to create.
@@ -1647,7 +2116,7 @@ private FileOutputStream openOutputStreamInternal(Long length, AccessCondition a
if (opContext == null) {
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient, false /* setStartTime */);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient, false /* setStartTime */);
if (length != null) {
if (options.getStoreFileContentMD5()) {
@@ -1669,7 +2138,7 @@ private FileOutputStream openOutputStreamInternal(Long length, AccessCondition a
}
/**
- * Uploads a file from data in a byte array.
+ * Uploads a file from data in a byte array. If the file already exists on the service, it will be overwritten.
*
* @param buffer
* A byte
array which represents the data to write to the file.
@@ -1688,7 +2157,7 @@ public void uploadFromByteArray(final byte[] buffer, final int offset, final int
}
/**
- * Uploads a file from data in a byte array.
+ * Uploads a file from data in a byte array. If the file already exists on the service, it will be overwritten.
*
* @param buffer
* A byte
array which represents the data to write to the file.
@@ -1720,7 +2189,7 @@ public void uploadFromByteArray(final byte[] buffer, final int offset, final int
}
/**
- * Uploads a file.
+ * Uploads a local file. If the file already exists on the service, it will be overwritten.
*
* @param path
* A String
which represents the path to the file to be uploaded.
@@ -1734,7 +2203,7 @@ public void uploadFromFile(final String path) throws StorageException, IOExcepti
}
/**
- * Uploads a file from a file.
+ * Uploads a file from a local file. If the file already exists on the service, it will be overwritten.
*
* @param path
* A String
which represents the path to the file to be uploaded.
@@ -1763,7 +2232,8 @@ public void uploadFromFile(final String path, final AccessCondition accessCondit
}
/**
- * Uploads a file from a string using the platform's default encoding.
+ * Uploads a file from a string using the platform's default encoding. If the file already exists on the service, it
+ * will be overwritten.
*
* @param content
* A String
which represents the content that will be uploaded to the file.
@@ -1777,7 +2247,8 @@ public void uploadText(final String content) throws StorageException, IOExceptio
}
/**
- * Uploads a file from a string using the specified encoding.
+ * Uploads a file from a string using the specified encoding. If the file already exists on the service, it will be
+ * overwritten.
*
* @param content
* A String
which represents the content that will be uploaded to the file.
@@ -1806,10 +2277,10 @@ public void uploadText(final String content, final String charsetName, final Acc
}
/**
- * Uploads a range to a file.
+ * Uploads a range to a file.
*
* @param sourceStream
- * An {@link IntputStream} object which represents the input stream to write to the file.
+ * An {@link InputStream} object which represents the input stream to write to the file.
* @param offset
* A long
which represents the offset, in number of bytes, at which to begin writing the
* data.
@@ -1831,7 +2302,7 @@ public void uploadRange(final InputStream sourceStream, final long offset, final
* Uploads a range to a file using the specified lease ID, request options, and operation context.
*
* @param sourceStream
- * An {@link IntputStream} object which represents the input stream to write to the file.
+ * An {@link InputStream} object which represents the input stream to write to the file.
* @param offset
* A long
which represents the offset, in number of bytes, at which to begin writing the
* data.
@@ -1861,7 +2332,7 @@ public void uploadRange(final InputStream sourceStream, final long offset, final
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
final FileRange range = new FileRange(offset, offset + length - 1);
final byte[] data = new byte[(int) length];
@@ -1929,8 +2400,8 @@ private void putRangeInternal(final FileRange range, final FileRangeOperationTyp
private StorageRequestlong
which represents the length, in bytes, of the stream data. Must be non zero.
*
@@ -2253,10 +2725,10 @@ public void upload(final InputStream sourceStream, final long length) throws Sto
/**
* Uploads the source stream data to the file using the specified access condition, request options, and operation
- * context.
+ * context. If the file already exists on the service, it will be overwritten.
*
* @param sourceStream
- * An {@link IntputStream} object to read from.
+ * An {@link InputStream} object to read from.
* @param length
* A long
which represents the length, in bytes, of the stream data. This must be great than
* zero.
@@ -2283,7 +2755,7 @@ public void upload(final InputStream sourceStream, final long length, final Acce
opContext = new OperationContext();
}
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
if (length <= 0) {
throw new IllegalArgumentException(SR.INVALID_FILE_LENGTH);
@@ -2351,7 +2823,7 @@ protected static String getParentNameFromURI(final StorageUri resourceAddress, f
}
else {
// Case 3 /true
if path-style URIs are used; otherwise, false
.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
* @throws StorageException
* If a storage service error occurred.
- * @throws URISyntaxException
*/
- private void parseURIQueryStringAndVerify(final StorageUri completeUri, final CloudFileClient existingClient,
- final boolean usePathStyleUri) throws StorageException, URISyntaxException {
- Utility.assertNotNull("completeUri", completeUri);
+ private void parseQueryAndVerify(final StorageUri completeUri, final StorageCredentials credentials)
+ throws StorageException {
+ Utility.assertNotNull("completeUri", completeUri);
if (!completeUri.isAbsolute()) {
- final String errorMessage = String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString());
- throw new IllegalArgumentException(errorMessage);
+ throw new IllegalArgumentException(String.format(SR.RELATIVE_ADDRESS_NOT_PERMITTED, completeUri.toString()));
}
this.storageUri = PathUtility.stripURIQueryAndFragment(completeUri);
- this.fileServiceClient = (existingClient == null) ? new CloudFileClient(
- PathUtility.getServiceClientBaseAddress(this.storageUri, usePathStyleUri), null) : existingClient;
- this.name = PathUtility.getFileNameFromURI(completeUri.getPrimaryUri(), usePathStyleUri);
+
+ final StorageCredentialsSharedAccessSignature parsedCredentials =
+ SharedAccessSignatureHelper.parseQuery(completeUri);
+
+ if (credentials != null && parsedCredentials != null) {
+ throw new IllegalArgumentException(SR.MULTIPLE_CREDENTIALS_PROVIDED);
+ }
+
+ try {
+ final boolean usePathStyleUris = Utility.determinePathStyleFromUri(this.storageUri.getPrimaryUri());
+ this.fileServiceClient = new CloudFileClient(PathUtility.getServiceClientBaseAddress(
+ this.getStorageUri(), usePathStyleUris), credentials != null ? credentials : parsedCredentials);
+ this.name = PathUtility.getFileNameFromURI(this.storageUri.getPrimaryUri(), usePathStyleUris);
+ }
+ catch (final URISyntaxException e) {
+ throw Utility.generateNewUnexpectedStorageException(e);
+ }
}
protected void updateEtagAndLastModifiedFromResponse(HttpURLConnection request) {
@@ -2419,6 +2901,7 @@ protected void updateLengthFromResponse(HttpURLConnection request) {
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
@Override
public final CloudFileShare getShare() throws StorageException, URISyntaxException {
if (this.share == null) {
@@ -2445,9 +2928,6 @@ public final HashMapString
that represents the name of the file.
*/
public final String getName() {
- if (Utility.isNullOrEmpty(this.name)) {
- this.name = PathUtility.getFileNameFromURI(this.getUri(), this.fileServiceClient.isUsePathStyleUris());
- }
return this.name;
}
@@ -2461,6 +2941,7 @@ public final String getName() {
* @throws URISyntaxException
* If the resource URI is invalid.
*/
+ @SuppressWarnings("deprecation")
@Override
public final CloudFileDirectory getParent() throws URISyntaxException, StorageException {
if (this.parent == null) {
@@ -2484,7 +2965,7 @@ public final FileProperties getProperties() {
}
/**
- * Returns the File service client associated with the file.
+ * Returns the file service client associated with the file.
*
* @return A {@link CloudFileClient} object that represents the client.
*/
@@ -2576,8 +3057,8 @@ protected void setStorageUri(final StorageUri storageUri) {
* Sets the minimum read size when using a {@link FileInputStream}.
*
* @param minimumReadSize
- * An int
that represents the minimum number of bytes to buffer when reading from a file
- * while using a {@link FileInputStream} object. Must be greater than or equal to 16 KB.
+ * An int
that represents the minimum number of bytes to buffer when reading from
+ * a file while using a {@link FileInputStream} object. Must be greater than or equal to 16 KB.
* @throws IllegalArgumentException
* If minimumReadSize
is less than 16 KB.
*/
@@ -2590,7 +3071,7 @@ public void setStreamMinimumReadSizeInBytes(final int minimumReadSize) {
}
/**
- * Sets the number of bytes to buffer when writing to a {@link FileOutoutStream}.
+ * Sets the number of bytes to buffer when writing to a {@link FileOutputStream}.
*
* @param streamWriteSizeInBytes
* An int
which represents the number of bytes to buffer while using a
@@ -2622,8 +3103,8 @@ public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes) {
* @throws URISyntaxException
* If the resource URI is invalid.
*/
- protected final StorageUri getTransformedAddress(final OperationContext opContext) throws URISyntaxException,
- StorageException {
+ protected final StorageUri getTransformedAddress(final OperationContext opContext)
+ throws URISyntaxException, StorageException {
return this.fileServiceClient.getCredentials().transformUri(this.getStorageUri(), opContext);
}
}
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileClient.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileClient.java
index 9d0b33fd58e4c..60ebcc78cba55 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileClient.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileClient.java
@@ -19,20 +19,20 @@
import java.net.URISyntaxException;
import com.microsoft.azure.storage.DoesServiceRequest;
-import com.microsoft.azure.storage.LocationMode;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.ResultContinuation;
import com.microsoft.azure.storage.ResultContinuationType;
import com.microsoft.azure.storage.ResultSegment;
-import com.microsoft.azure.storage.RetryExponentialRetry;
import com.microsoft.azure.storage.ServiceClient;
import com.microsoft.azure.storage.StorageCredentials;
+import com.microsoft.azure.storage.StorageCredentialsAnonymous;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.StorageUri;
import com.microsoft.azure.storage.core.ExecutionEngine;
import com.microsoft.azure.storage.core.LazySegmentedIterable;
import com.microsoft.azure.storage.core.ListResponse;
import com.microsoft.azure.storage.core.ListingContext;
+import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.core.SegmentedStorageRequest;
import com.microsoft.azure.storage.core.StorageRequest;
import com.microsoft.azure.storage.core.Utility;
@@ -48,7 +48,7 @@ public final class CloudFileClient extends ServiceClient {
/**
* Holds the default request option values associated with this Service Client.
*/
- private FileRequestOptions defaultRequestOptions;
+ private FileRequestOptions defaultRequestOptions = new FileRequestOptions();
/**
* Creates an instance of the CloudFileClient
class using the specified File service endpoint and
@@ -76,10 +76,10 @@ public CloudFileClient(final URI baseUri, StorageCredentials credentials) {
*/
public CloudFileClient(StorageUri storageUri, StorageCredentials credentials) {
super(storageUri, credentials);
- this.defaultRequestOptions = new FileRequestOptions();
- this.defaultRequestOptions.setLocationMode(LocationMode.PRIMARY_ONLY);
- this.defaultRequestOptions.setRetryPolicyFactory(new RetryExponentialRetry());
- this.defaultRequestOptions.setConcurrentRequestCount(FileConstants.DEFAULT_CONCURRENT_REQUEST_COUNT);
+ if (credentials == null || credentials.getClass().equals(StorageCredentialsAnonymous.class)) {
+ throw new IllegalArgumentException(SR.STORAGE_CREDENTIALS_NULL_OR_ANONYMOUS);
+ }
+ FileRequestOptions.applyDefaults(this.defaultRequestOptions);
}
/**
@@ -98,6 +98,7 @@ public CloudFileClient(StorageUri storageUri, StorageCredentials credentials) {
* @see Naming and Referencing Shares,
* Directories, Files, and Metadata
*/
+ @SuppressWarnings("deprecation")
public CloudFileShare getShareReference(final String shareName) throws URISyntaxException, StorageException {
Utility.assertNotNullOrEmpty("shareName", shareName);
return new CloudFileShare(shareName, this);
@@ -255,7 +256,7 @@ private Iterablenull
will use the default request options from the associated service client
+ * ({@link CloudFileClient}).
+ * @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 FileServiceProperties} object representing the current configuration of the service.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public final FileServiceProperties downloadServiceProperties(FileRequestOptions options, OperationContext opContext)
+ throws StorageException {
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ opContext.initialize();
+ options = FileRequestOptions.populateAndApplyDefaults(options, this);
+
+ return new FileServiceProperties(ExecutionEngine.executeWithRetry(
+ this, null, this.downloadServicePropertiesImpl(options, false),
+ options.getRetryPolicyFactory(), opContext));
+ }
+
+ /**
+ * Uploads a new {@link FileServiceProperties} configuration to the given storage service. This encapsulates
+ * the CORS configurations.
+ *
+ * @param properties
+ * A {@link FileServiceProperties} object which specifies the service properties to upload.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void uploadServiceProperties(final FileServiceProperties properties) throws StorageException {
+ this.uploadServiceProperties(properties, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Uploads a new {@link FileServiceProperties} configuration to the given storage service. This encapsulates
+ * the CORS configurations.
+ *
+ * @param properties
+ * A {@link FileServiceProperties} object which specifies the service properties to upload.
+ * @param options
+ * A {@link FileRequestOptions} object that specifies any additional options for the request. Specifying
+ * null
will use the default request options from the associated service client
+ * ({@link CloudFileClient}).
+ * @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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void uploadServiceProperties(final FileServiceProperties properties, FileRequestOptions options,
+ OperationContext opContext) throws StorageException {
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ opContext.initialize();
+ options = FileRequestOptions.populateAndApplyDefaults(options, this);
+
+ Utility.assertNotNull("properties", properties);
+
+ ExecutionEngine.executeWithRetry(this, null,
+ this.uploadServicePropertiesImpl(properties.getServiceProperties(), options, opContext, false),
+ options.getRetryPolicyFactory(), opContext);
+ }
+
/**
* Gets the {@link FileRequestOptions} that is used for requests associated with this CloudFileClient
*
@@ -403,7 +501,7 @@ public void setDefaultRequestOptions(FileRequestOptions defaultRequestOptions) {
Utility.assertNotNull("defaultRequestOptions", defaultRequestOptions);
this.defaultRequestOptions = defaultRequestOptions;
}
-
+
/**
* Indicates whether path-style URIs are being used.
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java
index bd3c1b04e2081..16937dfdeb848 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/file/CloudFileDirectory.java
@@ -20,6 +20,7 @@
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;
+import java.util.HashMap;
import com.microsoft.azure.storage.AccessCondition;
import com.microsoft.azure.storage.Constants;
@@ -28,6 +29,8 @@
import com.microsoft.azure.storage.ResultContinuation;
import com.microsoft.azure.storage.ResultContinuationType;
import com.microsoft.azure.storage.ResultSegment;
+import com.microsoft.azure.storage.StorageCredentials;
+import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.StorageUri;
@@ -39,17 +42,17 @@
import com.microsoft.azure.storage.core.RequestLocationMode;
import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.core.SegmentedStorageRequest;
+import com.microsoft.azure.storage.core.SharedAccessSignatureHelper;
import com.microsoft.azure.storage.core.StorageRequest;
import com.microsoft.azure.storage.core.Utility;
/**
* Represents a virtual directory of files.
* CloudFileDirectory
class using an absolute URI to the directory.
+ *
+ * @param directoryAbsoluteUri
+ * A {@link URI} that represents the file directory's address.
+ * @throws StorageException
+ */
+ public CloudFileDirectory(final URI directoryAbsoluteUri) throws StorageException {
+ this(new StorageUri(directoryAbsoluteUri));
+ }
+
+ /**
+ * Creates an instance of the CloudFileDirectory
class using an absolute URI to the directory.
+ *
+ * @param directoryAbsoluteUri
+ * A {@link StorageUri} that represents the file directory's address.
+ * @throws StorageException
+ */
+ public CloudFileDirectory(final StorageUri directoryAbsoluteUri) throws StorageException {
+ this(directoryAbsoluteUri, (StorageCredentials) null);
+ }
+
+ /**
+ * Creates an instance of the CloudFileDirectory
class using an absolute URI to the directory
+ * and credentials.
+ *
+ * @param directoryAbsoluteUri
+ * A {@link URI} that represents the file directory's address.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ */
+ public CloudFileDirectory(final URI directoryAbsoluteUri, final StorageCredentials credentials)
+ throws StorageException {
+ this(new StorageUri(directoryAbsoluteUri), credentials);
+ }
+ /**
+ * Creates an instance of the CloudFileDirectory
class using an absolute URI to the directory
+ * and credentials.
+ *
+ * @param directoryAbsoluteUri
+ * A {@link StorageUri} that represents the file directory's address.
+ * @param credentials
+ * A {@link StorageCredentials} object used to authenticate access.
+ * @throws StorageException
+ */
+ public CloudFileDirectory(final StorageUri directoryAbsoluteUri, final StorageCredentials credentials)
+ throws StorageException {
+ this.parseQueryAndVerify(directoryAbsoluteUri, credentials);
+ }
+
/**
* Creates an instance of the CloudFileDirectory
class using an absolute URI to the directory.
*
@@ -89,7 +149,9 @@ public final class CloudFileDirectory implements ListFileItem {
* A {@link CloudFileClient} object that represents the associated service client.
* @throws StorageException
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFileDirectory#CloudFileDirectory(URI, StorageCredentials)}
*/
+ @Deprecated
public CloudFileDirectory(final URI directoryAbsoluteUri, final CloudFileClient client) throws StorageException,
URISyntaxException {
this(new StorageUri(directoryAbsoluteUri), client);
@@ -104,19 +166,17 @@ public CloudFileDirectory(final URI directoryAbsoluteUri, final CloudFileClient
* A {@link CloudFileClient} object that represents the associated service client.
* @throws StorageException
* @throws URISyntaxException
+ * @deprecated as of 3.0.0. Please use {@link CloudFileDirectory#CloudFileDirectory(StorageUri, StorageCredentials)}
*/
+ @Deprecated
public CloudFileDirectory(final StorageUri directoryAbsoluteUri, final CloudFileClient client)
throws StorageException, URISyntaxException {
- Utility.assertNotNull("directoryAbsoluteUri", directoryAbsoluteUri);
+ this.parseQueryAndVerify(directoryAbsoluteUri, client == null ? null : client.getCredentials());
- this.fileServiceClient = client;
- this.storageUri = directoryAbsoluteUri;
- this.properties = new FileDirectoryProperties();
- this.parseQueryAndVerify(
- directoryAbsoluteUri,
- client,
- client == null ? Utility.determinePathStyleFromUri(this.storageUri.getPrimaryUri()) : client
- .isUsePathStyleUris());
+ // Override the client set in parseQueryAndVerify to make sure request options are propagated.
+ if (client != null) {
+ this.fileServiceClient = client;
+ }
}
/**
@@ -139,7 +199,6 @@ protected CloudFileDirectory(final StorageUri uri, final String directoryName, f
this.fileServiceClient = share.getServiceClient();
this.share = share;
this.storageUri = uri;
- this.properties = new FileDirectoryProperties();
}
/**
@@ -175,7 +234,7 @@ public void create(FileRequestOptions options, OperationContext opContext) throw
}
opContext.initialize();
- options = FileRequestOptions.applyDefaults(options, this.fileServiceClient);
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
ExecutionEngine.executeWithRetry(this.fileServiceClient, this, createDirectoryImpl(options),
options.getRetryPolicyFactory(), opContext);
@@ -183,8 +242,8 @@ public void create(FileRequestOptions options, OperationContext opContext) throw
private StorageRequestnull
will use the default request options from the associated service client (
+ * {@link CloudFileClient}).
+ * @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.
+ *
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void uploadMetadata(AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext)
+ throws StorageException {
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ opContext.initialize();
+ options = FileRequestOptions.populateAndApplyDefaults(options, this.fileServiceClient);
+
+ ExecutionEngine.executeWithRetry(this.fileServiceClient, this,
+ this.uploadMetadataImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext);
+ }
+
+ private StorageRequest