diff --git a/ChangeLog.txt b/ChangeLog.txt
index 7fe17ea69bbf5..b16680c08803d 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,6 @@
+2017.XX.XX Version X.X.X
+ * For Standard Storage Accounts only, added the ability to set the tier of individual block blobs. The tier can currently only be set through uploadTier()
+
2017.07.12 Version 5.4.0
* Added ErrorReceivingResponseEvent which fires when a network error occurs before the responseReceivedEvent fires. If the responseReceivedEvent fires sucessfully, this new event will not fire.
* For Premium Accounts only, added support for getting and setting the tier on a page blob. The tier can also be set when creating or copying from an existing page blob.
diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java
index c62f29da77a4d..579d46b8e6293 100644
--- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java
+++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlockBlobTests.java
@@ -48,15 +48,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.TimeZone;
+import java.util.*;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.TestRunners.CloudTests;
@@ -1942,4 +1934,82 @@ private void doCloudBlockBlobCopy(boolean sourceIsSas, boolean destinationIsSas)
destination.delete();
source.delete();
}
+
+ @Test
+ @Category({ DevFabricTests.class, DevStoreTests.class })
+ public void testCloudBlockBlobUploadStandardTier() throws StorageException, IOException, URISyntaxException {
+ for (StandardBlobTier standardBlobTier : StandardBlobTier.values()) {
+ if (standardBlobTier == StandardBlobTier.UNKNOWN) {
+ continue;
+ }
+
+ final String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlob");
+ final CloudBlockBlob blob = this.container.getBlockBlobReference(blobName);
+ blob.uploadText("text");
+
+ blob.uploadStandardBlobTier(standardBlobTier);
+ assertEquals(standardBlobTier, blob.getProperties().getStandardBlobTier());
+ assertNull(blob.getProperties().getPremiumPageBlobTier());
+ assertNull(blob.getProperties().getRehydrationStatus());
+
+ CloudBlockBlob blob2 = this.container.getBlockBlobReference(blobName);
+ blob2.downloadAttributes();
+ assertEquals(standardBlobTier, blob2.getProperties().getStandardBlobTier());
+ assertNull(blob2.getProperties().getPremiumPageBlobTier());
+ assertNull(blob2.getProperties().getRehydrationStatus());
+
+ CloudBlockBlob blob3 = (CloudBlockBlob)this.container.listBlobs().iterator().next();
+ assertEquals(standardBlobTier, blob3.getProperties().getStandardBlobTier());
+ assertNull(blob3.getProperties().getPremiumPageBlobTier());
+ assertNull(blob3.getProperties().getRehydrationStatus());
+
+ blob.deleteIfExists();
+ }
+ }
+
+ @Test
+ @Category({ DevFabricTests.class, DevStoreTests.class })
+ public void testCloudBlockBlobRehydrateBlob() throws StorageException, IOException, URISyntaxException {
+ final String blobName1 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlob1");
+ final String blobName2 = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlob2");
+ final CloudBlockBlob blob = this.container.getBlockBlobReference(blobName1);
+ blob.uploadText("text");
+ blob.uploadStandardBlobTier(StandardBlobTier.ARCHIVE);
+ final CloudBlockBlob blob2 = this.container.getBlockBlobReference(blobName2);
+ blob2.uploadText("text");
+ blob2.uploadStandardBlobTier(StandardBlobTier.ARCHIVE);
+
+ CloudBlockBlob blobRef1 = this.container.getBlockBlobReference(blobName1);
+ blobRef1.uploadStandardBlobTier(StandardBlobTier.COOL);
+ assertNull(blobRef1.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, blobRef1.getProperties().getStandardBlobTier());
+ assertNull(blobRef1.getProperties().getPremiumPageBlobTier());
+
+ blob.downloadAttributes();
+ assertEquals(RehydrationStatus.PENDING_TO_COOL, blob.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, blob.getProperties().getStandardBlobTier());
+ assertNull(blob.getProperties().getPremiumPageBlobTier());
+
+ CloudBlockBlob blobRef2 = this.container.getBlockBlobReference(blobName2);
+ blobRef2.uploadStandardBlobTier(StandardBlobTier.HOT);
+ assertNull(blobRef2.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, blobRef2.getProperties().getStandardBlobTier());
+ assertNull(blobRef2.getProperties().getPremiumPageBlobTier());
+
+ blob2.downloadAttributes();
+ assertEquals(RehydrationStatus.PENDING_TO_HOT, blob2.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, blob2.getProperties().getStandardBlobTier());
+ assertNull(blob2.getProperties().getPremiumPageBlobTier());
+
+ Iterator it = this.container.listBlobs().iterator();
+ CloudBlockBlob listBlob = (CloudBlockBlob)it.next();
+ assertEquals(RehydrationStatus.PENDING_TO_COOL, listBlob.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, listBlob.getProperties().getStandardBlobTier());
+ assertNull(listBlob.getProperties().getPremiumPageBlobTier());
+
+ CloudBlockBlob listBlob2 = (CloudBlockBlob)it.next();
+ assertEquals(RehydrationStatus.PENDING_TO_HOT, listBlob2.getProperties().getRehydrationStatus());
+ assertEquals(StandardBlobTier.ARCHIVE, listBlob2.getProperties().getStandardBlobTier());
+ assertNull(listBlob2.getProperties().getPremiumPageBlobTier());
+ }
}
diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java
index c8657699d40a5..6ade1eb60b60e 100644
--- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java
+++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudPageBlobTests.java
@@ -1242,39 +1242,47 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept
// Test create API
CloudPageBlob blob = container.getPageBlobReference(blobName);
- assertNull(blob.getProperties().getInferredBlobTier());
+ assertNull(blob.getProperties().isBlobTierInferred());
blob.create(1024, PremiumPageBlobTier.P4, null, null, null);
assertEquals(PremiumPageBlobTier.P4, blob.getProperties().getPremiumPageBlobTier());
- assertFalse(blob.getProperties().getInferredBlobTier());
+ assertFalse(blob.getProperties().isBlobTierInferred());
+ assertNull(blob.getProperties().getStandardBlobTier());
+ assertNull(blob.getProperties().getRehydrationStatus());
CloudPageBlob blob2 = container.getPageBlobReference(blobName);
blob2.downloadAttributes();
assertEquals(PremiumPageBlobTier.P4, blob2.getProperties().getPremiumPageBlobTier());
- assertNull(blob2.getProperties().getInferredBlobTier());
+ assertNull(blob2.getProperties().isBlobTierInferred());
+ assertNull(blob2.getProperties().getStandardBlobTier());
+ assertNull(blob2.getProperties().getRehydrationStatus());
// Test upload from byte array API
byte[] buffer = BlobTestHelper.getRandomBuffer(1024);
CloudPageBlob blob3 = container.getPageBlobReference("blob3");
blob3.uploadFromByteArray(buffer, 0, 1024, PremiumPageBlobTier.P6, null, null, null);
assertEquals(PremiumPageBlobTier.P6, blob3.getProperties().getPremiumPageBlobTier());
- assertFalse(blob3.getProperties().getInferredBlobTier());
+ assertFalse(blob3.getProperties().isBlobTierInferred());
+ assertNull(blob3.getProperties().getStandardBlobTier());
+ assertNull(blob3.getProperties().getRehydrationStatus());
CloudPageBlob blob3Ref = container.getPageBlobReference("blob3");
blob3Ref.downloadAttributes();
assertEquals(PremiumPageBlobTier.P6, blob3Ref.getProperties().getPremiumPageBlobTier());
- assertNull(blob3Ref.getProperties().getInferredBlobTier());
+ assertNull(blob3Ref.getProperties().isBlobTierInferred());
// Test upload from stream API
ByteArrayInputStream srcStream = new ByteArrayInputStream(buffer);
CloudPageBlob blob4 = container.getPageBlobReference("blob4");
blob4.upload(srcStream, 1024, PremiumPageBlobTier.P10, null, null, null);
assertEquals(PremiumPageBlobTier.P10, blob4.getProperties().getPremiumPageBlobTier());
- assertFalse(blob4.getProperties().getInferredBlobTier());
+ assertFalse(blob4.getProperties().isBlobTierInferred());
+ assertNull(blob4.getProperties().getStandardBlobTier());
+ assertNull(blob4.getProperties().getRehydrationStatus());
CloudPageBlob blob4Ref = container.getPageBlobReference("blob4");
blob4Ref.downloadAttributes();
assertEquals(PremiumPageBlobTier.P10, blob4Ref.getProperties().getPremiumPageBlobTier());
- assertNull(blob4Ref.getProperties().getInferredBlobTier());
+ assertNull(blob4Ref.getProperties().isBlobTierInferred());
// Test upload from file API
File sourceFile = File.createTempFile("sourceFile", ".tmp");
@@ -1286,12 +1294,14 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept
CloudPageBlob blob5 = container.getPageBlobReference("blob5");
blob5.uploadFromFile(sourceFile.getAbsolutePath(), PremiumPageBlobTier.P20, null, null, null);
assertEquals(PremiumPageBlobTier.P20, blob5.getProperties().getPremiumPageBlobTier());
- assertFalse(blob5.getProperties().getInferredBlobTier());
+ assertFalse(blob5.getProperties().isBlobTierInferred());
+ assertNull(blob5.getProperties().getStandardBlobTier());
+ assertNull(blob5.getProperties().getRehydrationStatus());
CloudPageBlob blob5Ref = container.getPageBlobReference("blob5");
blob5Ref.downloadAttributes();
assertEquals(PremiumPageBlobTier.P20, blob5Ref.getProperties().getPremiumPageBlobTier());
- assertNull(blob5Ref.getProperties().getInferredBlobTier());
+ assertNull(blob5Ref.getProperties().isBlobTierInferred());
}
finally {
container.deleteIfExists();
@@ -1307,19 +1317,21 @@ public void testCloudPageBlobSetBlobTier() throws URISyntaxException, StorageExc
String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob");
CloudPageBlob blob = container.getPageBlobReference(blobName);
blob.create(1024);
- assertNull(blob.getProperties().getInferredBlobTier());
+ assertNull(blob.getProperties().isBlobTierInferred());
blob.downloadAttributes();
- assertTrue(blob.getProperties().getInferredBlobTier());
+ assertTrue(blob.getProperties().isBlobTierInferred());
assertEquals(PremiumPageBlobTier.P10, blob.getProperties().getPremiumPageBlobTier());
blob.uploadPremiumPageBlobTier(PremiumPageBlobTier.P40);
assertEquals(PremiumPageBlobTier.P40, blob.properties.getPremiumPageBlobTier());
- assertFalse(blob.getProperties().getInferredBlobTier());
+ assertFalse(blob.getProperties().isBlobTierInferred());
+ assertNull(blob.getProperties().getStandardBlobTier());
+ assertNull(blob.getProperties().getRehydrationStatus());
CloudPageBlob blob2 = container.getPageBlobReference(blobName);
blob2.downloadAttributes();
assertEquals(PremiumPageBlobTier.P40, blob2.properties.getPremiumPageBlobTier());
- assertNull(blob2.getProperties().getInferredBlobTier());
+ assertNull(blob2.getProperties().isBlobTierInferred());
boolean pageBlobWithTierFound = false;
for (ListBlobItem blobItem : container.listBlobs()) {
@@ -1328,7 +1340,9 @@ public void testCloudPageBlobSetBlobTier() throws URISyntaxException, StorageExc
if (blob.getName().equals(blobName) && !pageBlobWithTierFound) {
// Check that the blob is found exactly once
assertEquals(PremiumPageBlobTier.P40, blob3.properties.getPremiumPageBlobTier());
- assertFalse(blob3.getProperties().getInferredBlobTier());
+ assertNull(blob3.getProperties().isBlobTierInferred());
+ assertNull(blob3.getProperties().getStandardBlobTier());
+ assertNull(blob3.getProperties().getRehydrationStatus());
pageBlobWithTierFound = true;
} else if (blob.getName().equals(blobName)) {
fail("Page blob found twice");
@@ -1379,14 +1393,18 @@ public void testCloudPageBlobSetBlobTierOnCopy() throws URISyntaxException, Stor
assertEquals(BlobType.PAGE_BLOB, copy.getProperties().getBlobType());
assertEquals(PremiumPageBlobTier.P30, copy.getProperties().getPremiumPageBlobTier());
assertEquals(PremiumPageBlobTier.P10, source.getProperties().getPremiumPageBlobTier());
- assertFalse(source.getProperties().getInferredBlobTier());
- assertFalse(copy.getProperties().getInferredBlobTier());
+ assertFalse(source.getProperties().isBlobTierInferred());
+ assertFalse(copy.getProperties().isBlobTierInferred());
+ assertNull(source.getProperties().getStandardBlobTier());
+ assertNull(source.getProperties().getRehydrationStatus());
+ assertNull(copy.getProperties().getStandardBlobTier());
+ assertNull(copy.getProperties().getRehydrationStatus());
BlobTestHelper.waitForCopy(copy);
CloudPageBlob copyRef = container.getPageBlobReference("copy");
copyRef.downloadAttributes();
assertEquals(PremiumPageBlobTier.P30, copyRef.getProperties().getPremiumPageBlobTier());
- assertNull(copyRef.getProperties().getInferredBlobTier());
+ assertNull(copyRef.getProperties().isBlobTierInferred());
// copy where source does not have a tier
CloudPageBlob source2 = container.getPageBlobReference("source2");
@@ -1397,8 +1415,12 @@ public void testCloudPageBlobSetBlobTierOnCopy() throws URISyntaxException, Stor
assertEquals(BlobType.PAGE_BLOB, copy3.getProperties().getBlobType());
assertEquals(PremiumPageBlobTier.P60, copy3.getProperties().getPremiumPageBlobTier());
assertNull(source2.getProperties().getPremiumPageBlobTier());
- assertNull(source2.getProperties().getInferredBlobTier());
- assertFalse(copy3.getProperties().getInferredBlobTier());
+ assertNull(source2.getProperties().isBlobTierInferred());
+ assertFalse(copy3.getProperties().isBlobTierInferred());
+ assertNull(source2.getProperties().getStandardBlobTier());
+ assertNull(source2.getProperties().getRehydrationStatus());
+ assertNull(copy3.getProperties().getStandardBlobTier());
+ assertNull(copy3.getProperties().getRehydrationStatus());
}
finally {
container.deleteIfExists();
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java
index 278150e9e9f65..68ba8b0a7967f 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java
@@ -899,6 +899,11 @@ public static class QueryConstants {
*/
public static final String ACCESS_TIER = "AccessTier";
+ /**
+ * XML element for the archive status.
+ */
+ public static final String ARCHIVE_STATUS = "ArchiveStatus";
+
/**
* Buffer width used to copy data to output streams.
*/
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobConstants.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobConstants.java
index 603e513644cb3..102bbd4bdc974 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobConstants.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/BlobConstants.java
@@ -30,11 +30,17 @@ final class BlobConstants {
* The header that specifies if the access tier is inferred.
*/
public static final String ACCESS_TIER_INFERRED_HEADER = Constants.PREFIX_FOR_STORAGE_HEADER + "access-tier-inferred";
+
/**
* Specifies the append blob type.
*/
public static final String APPEND_BLOB = "AppendBlob";
+ /**
+ * The header that specifies the archive status.
+ */
+ public static final String ARCHIVE_STATUS_HEADER = Constants.PREFIX_FOR_STORAGE_HEADER + "archive-status";
+
/**
* XML element for authentication error details.
*/
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 1898af48aad70..5fe51e3f866ae 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
@@ -325,9 +325,31 @@ else if (Constants.COPY_DESTINATION_SNAPSHOT_ID_ELEMENT.equals(currentNode)) {
this.copyState.setCopyDestinationSnapshotID(value);
}
else if (Constants.ACCESS_TIER.equals(currentNode)) {
- PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(value);
- this.properties.setPremiumPageBlobTier(premiumPageBlobTier);
- this.properties.setBlobTierInferredTier(false);
+ if (properties.getBlobType().equals(BlobType.PAGE_BLOB)) {
+ PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(value);
+ this.properties.setPremiumPageBlobTier(premiumPageBlobTier);
+ }
+ else if (properties.getBlobType().equals(BlobType.BLOCK_BLOB)) {
+ StandardBlobTier standardBlobTier = StandardBlobTier.parse(value);
+ this.properties.setStandardBlobTier(standardBlobTier);
+ }
+ else if (properties.getBlobType().equals(BlobType.UNSPECIFIED)) {
+ PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(value);
+ StandardBlobTier standardBlobTier = StandardBlobTier.parse(value);
+ if (!premiumPageBlobTier.equals(PremiumPageBlobTier.UNKNOWN)) {
+ properties.setPremiumPageBlobTier(premiumPageBlobTier);
+ }
+ else if (!standardBlobTier.equals(StandardBlobTier.UNKNOWN)) {
+ properties.setStandardBlobTier(standardBlobTier);
+ }
+ else {
+ properties.setPremiumPageBlobTier(PremiumPageBlobTier.UNKNOWN);
+ properties.setStandardBlobTier(StandardBlobTier.UNKNOWN);
+ }
+ }
+ }
+ else if (Constants.ARCHIVE_STATUS.equals(currentNode)) {
+ this.properties.setRehydrationStatus(RehydrationStatus.parse(value));
}
}
}
\ No newline at end of file
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 0c227c48945bb..3c645e3a4ce87 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
@@ -122,11 +122,21 @@ public final class BlobProperties {
*/
private PremiumPageBlobTier premiumPageBlobTier;
+ /**
+ * Represents the tier on a blob on a standard storage account.
+ */
+ private StandardBlobTier standardBlobTier;
+
/**
* Represents whether or not the blob tier is inferred.
*/
private Boolean isBlobTierInferredTier;
-
+
+ /**
+ * Represents the rehydration status if the blob is being rehydrated.
+ */
+ private RehydrationStatus rehydrationStatus;
+
/**
* Creates an instance of the BlobProperties
class.
*/
@@ -152,16 +162,18 @@ public BlobProperties(final BlobProperties other) {
this.contentType = other.contentType;
this.copyState = other.copyState;
this.etag = other.etag;
+ this.isBlobTierInferredTier = other.isBlobTierInferredTier;
+ this.isIncrementalCopy = other.isIncrementalCopy;
this.leaseStatus = other.leaseStatus;
this.leaseState = other.leaseState;
this.leaseDuration = other.leaseDuration;
this.length = other.length;
this.lastModified = other.lastModified;
this.pageBlobSequenceNumber = other.pageBlobSequenceNumber;
- this.serverEncrypted = other.serverEncrypted;
- this.isIncrementalCopy = other.isIncrementalCopy;
this.premiumPageBlobTier = other.premiumPageBlobTier;
- this.isBlobTierInferredTier = other.isBlobTierInferredTier;
+ this.serverEncrypted = other.serverEncrypted;
+ this.standardBlobTier = other.standardBlobTier;
+ this.rehydrationStatus = other.rehydrationStatus;
}
/**
@@ -288,7 +300,7 @@ public Date getLastModified() {
*
* @return A {@Link java.lang.Boolean} object which represents if the blob tier was inferred.
*/
- public Boolean getInferredBlobTier() { return this.isBlobTierInferredTier; }
+ public Boolean isBlobTierInferred() { return this.isBlobTierInferredTier; }
/**
* Gets the lease status for the blob.
@@ -344,6 +356,22 @@ public PremiumPageBlobTier getPremiumPageBlobTier() {
return this.premiumPageBlobTier;
}
+ /**
+ * If using a standard account and the blob is a block blob, gets the tier of the blob.
+ * @return A {@link StandardBlobTier} object which represents the tier of the blob
+ * or null
if the tier has not been set.
+ */
+ public StandardBlobTier getStandardBlobTier() {
+ return this.standardBlobTier;
+ }
+
+ /**
+ * The rehydration status if the blob is being rehydrated
+ * and the tier of the blob once the rehydration from archive has completed.
+ * @return
+ */
+ public RehydrationStatus getRehydrationStatus() { return this.rehydrationStatus; }
+
/**
* Gets the blob's server-side encryption status;
*
@@ -550,12 +578,30 @@ protected void setPremiumPageBlobTier(PremiumPageBlobTier premiumPageBlobTier) {
this.premiumPageBlobTier = premiumPageBlobTier;
}
+ /**
+ * Sets the tier of the block blob. This is only supported for standard storage accounts.
+ * @param standardBlobTier
+ * A {@link StandardBlobTier} object which represents the tier of the blob.
+ */
+ protected void setStandardBlobTier(StandardBlobTier standardBlobTier) {
+ this.standardBlobTier = standardBlobTier;
+ }
+
/**
* Sets whether the blob tier is inferred.
* @param isBlobTierInferredTier
* A {@Link java.lang.Boolean} which specifies if the blob tier is inferred.
*/
- protected void setBlobTierInferredTier(Boolean isBlobTierInferredTier) {
+ protected void setBlobTierInferred(Boolean isBlobTierInferredTier) {
this.isBlobTierInferredTier = isBlobTierInferredTier;
}
+
+ /**
+ * Sets the rehydration status of the blob.
+ * @param rehydrationStatus
+ * A {@Link RehydrationStatus} which specifies the rehydration status of the blob.
+ */
+ protected void setRehydrationStatus(RehydrationStatus rehydrationStatus) {
+ this.rehydrationStatus = rehydrationStatus;
+ }
}
\ No newline at end of file
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 0e26efa41847d..70b38e691c5fe 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
@@ -125,23 +125,43 @@ else if (!Utility.isNullOrEmpty(xContentLengthHeader)) {
}
// Get the tier of the blob
- final String premiumBlobTierString = request.getHeaderField(BlobConstants.ACCESS_TIER_HEADER);
+ final String blobTierString = request.getHeaderField(BlobConstants.ACCESS_TIER_HEADER);
- if (properties.getBlobType().equals(BlobType.PAGE_BLOB))
- {
- PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(premiumBlobTierString);
+ if (!Utility.isNullOrEmpty(blobTierString) && properties.getBlobType().equals(BlobType.PAGE_BLOB)) {
+ PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(blobTierString);
properties.setPremiumPageBlobTier(premiumPageBlobTier);
}
- else if (properties.getBlobType().equals(BlobType.UNSPECIFIED)) {
- PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(premiumBlobTierString);
+ else if (!Utility.isNullOrEmpty(blobTierString) && properties.getBlobType().equals(BlobType.BLOCK_BLOB)) {
+ StandardBlobTier standardBlobTier = StandardBlobTier.parse(blobTierString);
+ properties.setStandardBlobTier(standardBlobTier);
+ }
+ else if (!Utility.isNullOrEmpty(blobTierString) && properties.getBlobType().equals(BlobType.UNSPECIFIED)) {
+ PremiumPageBlobTier premiumPageBlobTier = PremiumPageBlobTier.parse(blobTierString);
+ StandardBlobTier standardBlobTier = StandardBlobTier.parse(blobTierString);
if (!premiumPageBlobTier.equals(PremiumPageBlobTier.UNKNOWN)) {
properties.setPremiumPageBlobTier(premiumPageBlobTier);
}
+ else if (!standardBlobTier.equals(StandardBlobTier.UNKNOWN)) {
+ properties.setStandardBlobTier(standardBlobTier);
+ }
+ else {
+ properties.setPremiumPageBlobTier(PremiumPageBlobTier.UNKNOWN);
+ properties.setStandardBlobTier(StandardBlobTier.UNKNOWN);
+ }
}
final String tierInferredString = request.getHeaderField(BlobConstants.ACCESS_TIER_INFERRED_HEADER);
if (!Utility.isNullOrEmpty(tierInferredString)) {
- properties.setBlobTierInferredTier(Boolean.parseBoolean(tierInferredString));
+ properties.setBlobTierInferred(Boolean.parseBoolean(tierInferredString));
+ }
+
+ final String rehydrationStatusString = request.getHeaderField(BlobConstants.ARCHIVE_STATUS_HEADER);
+ if (!Utility.isNullOrEmpty(rehydrationStatusString)) {
+ RehydrationStatus rehydrationStatus = RehydrationStatus.parse(rehydrationStatusString);
+ properties.setRehydrationStatus(rehydrationStatus);
+ }
+ else {
+ properties.setRehydrationStatus(null);
}
final String incrementalCopyHeaderString =
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 ad64655b3a56b..4e5926ede8ae6 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
@@ -772,7 +772,7 @@ public String preProcessResponse(CloudBlob blob, CloudBlobClient client, Operati
blob.properties.setCopyState(BlobResponse.getCopyState(this.getConnection()));
blob.properties.setPremiumPageBlobTier(premiumPageBlobTier);
if (premiumPageBlobTier != null) {
- blob.properties.setBlobTierInferredTier(false);
+ blob.properties.setBlobTierInferred(false);
}
return blob.properties.getCopyState().getCopyId();
@@ -2600,6 +2600,56 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
return putRequest;
}
+ protected StorageRequest uploadBlobTierImpl(final String blobTierString, final BlobRequestOptions options) {
+ final StorageRequest setTierRequest = new StorageRequest(
+ options, this.getStorageUri()) {
+
+ @Override
+ public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, OperationContext context)
+ throws Exception {
+ return BlobRequest.setBlobTier(blob.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, blobTierString);
+ }
+
+ @Override
+ public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
+ throws Exception {
+ StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
+ }
+
+ @Override
+ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, OperationContext context)
+ throws Exception {
+ if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK && this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) {
+ this.setNonExceptionedRetryableFailure(true);
+ return null;
+ }
+
+ blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
+ this.getResult().setRequestServiceEncrypted(BaseResponse.isServerRequestEncrypted(this.getConnection()));
+ blob.getProperties().setBlobTierInferred(false);
+ if (blob.getProperties().getBlobType() == BlobType.BLOCK_BLOB) {
+ // For standard accounts when rehydrating a blob from archive, the status code will be 202 instead of 200.
+ StandardBlobTier standardBlobTier = StandardBlobTier.parse(blobTierString);
+ blob.getProperties().setRehydrationStatus(null);
+ if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) {
+ blob.getProperties().setStandardBlobTier(standardBlobTier);
+ }
+ else if (standardBlobTier.equals(StandardBlobTier.COOL)) {
+ blob.getProperties().setStandardBlobTier(StandardBlobTier.ARCHIVE);
+ }
+ else if (standardBlobTier.equals(StandardBlobTier.HOT)) {
+ blob.getProperties().setStandardBlobTier(StandardBlobTier.ARCHIVE);
+ }
+ }
+
+ return null;
+ }
+
+ };
+
+ return setTierRequest;
+ }
+
/**
* Sets the container for the blob.
*
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java
index 411752dcd7459..94e70ebab9599 100644
--- a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/CloudBlockBlob.java
@@ -1240,6 +1240,49 @@ public void setStreamWriteSizeInBytes(final int streamWriteSizeInBytes)
this.isStreamWriteSizeModified = true;
}
+ /**
+ * Sets the blob tier on a block blob on a standard storage account.
+ * @param standardBlobTier
+ * A {@link StandardBlobTier} object which represents the tier of the blob.
+ * @throws StorageException
+ * If a storage service error occurred.
+ */
+ @DoesServiceRequest
+ public void uploadStandardBlobTier(final StandardBlobTier standardBlobTier) throws StorageException {
+ this.uploadStandardBlobTier(standardBlobTier, null /* options */, null /* opContext */);
+ }
+
+ /**
+ * Sets the tier on a block blob on a standard storage account.
+ * @param standardBlobTier
+ * A {@link StandardBlobTier} object which represents the tier of 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.
+ */
+ @DoesServiceRequest
+ public void uploadStandardBlobTier(final StandardBlobTier standardBlobTier, BlobRequestOptions options,
+ OperationContext opContext) throws StorageException {
+ assertNoWriteOperationForSnapshot();
+ Utility.assertNotNull("standardBlobTier", standardBlobTier);
+
+ if (opContext == null) {
+ opContext = new OperationContext();
+ }
+
+ options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.BLOCK_BLOB, this.blobServiceClient);
+
+ ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
+ this.uploadBlobTierImpl(standardBlobTier.toString(), options), options.getRetryPolicyFactory(), opContext);
+ }
+
/**
* Gets the flag that indicates whether the default streamWriteSize was modified.
*/
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 8553b05198379..6296b9a089876 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
@@ -580,7 +580,7 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation
blob.getProperties().setLength(length);
blob.getProperties().setPremiumPageBlobTier(premiumBlobTier);
if (premiumBlobTier != null) {
- blob.getProperties().setBlobTierInferredTier(false);
+ blob.getProperties().setBlobTierInferred(false);
}
return null;
@@ -1611,43 +1611,8 @@ public void uploadPremiumPageBlobTier(final PremiumPageBlobTier premiumBlobTier,
options = BlobRequestOptions.populateAndApplyDefaults(options, BlobType.PAGE_BLOB, this.blobServiceClient);
ExecutionEngine.executeWithRetry(this.blobServiceClient, this,
- this.uploadPremiumPageBlobTierImpl(premiumBlobTier, options), options.getRetryPolicyFactory(), opContext);
- }
-
- private StorageRequest uploadPremiumPageBlobTierImpl(final PremiumPageBlobTier premiumBlobTier,
- final BlobRequestOptions options) {
- final StorageRequest setTierRequest = new StorageRequest(
- options, this.getStorageUri()) {
-
- @Override
- public HttpURLConnection buildRequest(CloudBlobClient client, CloudBlob blob, OperationContext context)
- throws Exception {
- return BlobRequest.setBlobTier(blob.getTransformedAddress(context).getUri(this.getCurrentLocation()), options, context, premiumBlobTier.toString());
- }
-
- @Override
- public void signRequest(HttpURLConnection connection, CloudBlobClient client, OperationContext context)
- throws Exception {
- StorageRequest.signBlobQueueAndFileRequest(connection, client, 0L, context);
- }
-
- @Override
- public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, OperationContext context)
- throws Exception {
- if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) {
- this.setNonExceptionedRetryableFailure(true);
- return null;
- }
-
- blob.updateEtagAndLastModifiedFromResponse(this.getConnection());
- blob.properties.setPremiumPageBlobTier(premiumBlobTier);
- blob.properties.setBlobTierInferredTier(false);
-
- return null;
- }
-
- };
-
- return setTierRequest;
+ this.uploadBlobTierImpl(premiumBlobTier.toString(), options), options.getRetryPolicyFactory(), opContext);
+ this.properties.setPremiumPageBlobTier(premiumBlobTier);
+ this.properties.setBlobTierInferred(false);
}
}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/RehydrationStatus.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/RehydrationStatus.java
new file mode 100644
index 0000000000000..34f176d73caca
--- /dev/null
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/RehydrationStatus.java
@@ -0,0 +1,49 @@
+package com.microsoft.azure.storage.blob;
+
+import com.microsoft.azure.storage.core.Utility;
+
+import java.util.Locale;
+
+/**
+ * The rehydration status for the blob that is currently archived.
+ * Only applicable for block blobs on standard storage accounts for this version.
+ */
+public enum RehydrationStatus {
+ /**
+ * The rehydration status is not recognized by this version of the library.
+ */
+ UNKNOWN,
+
+ /**
+ * The blob is being rehydrated to hot storage.
+ */
+ PENDING_TO_HOT,
+
+ /**
+ * The blob is being rehydrated to cool storage.
+ **/
+ PENDING_TO_COOL;
+
+ /**
+ * Parses a rehydration status from the given string.
+ *
+ * @param rehydrationStatusString
+ * A String
which represents the rehydration status to string.
+ *
+ * @return A RehydrationStatus
value that represents the rehydration status of the blob.
+ */
+ protected static RehydrationStatus parse(final String rehydrationStatusString) {
+ if (Utility.isNullOrEmpty(rehydrationStatusString)) {
+ return UNKNOWN;
+ }
+ else if ("rehydrate-pending-to-hot".equals(rehydrationStatusString.toLowerCase(Locale.US))) {
+ return PENDING_TO_HOT;
+ }
+ else if ("rehydrate-pending-to-cool".equals(rehydrationStatusString.toLowerCase(Locale.US))) {
+ return PENDING_TO_COOL;
+ }
+ else {
+ return UNKNOWN;
+ }
+ }
+}
\ No newline at end of file
diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/StandardBlobTier.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/StandardBlobTier.java
new file mode 100644
index 0000000000000..251c859871c50
--- /dev/null
+++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/blob/StandardBlobTier.java
@@ -0,0 +1,70 @@
+/**
+ * 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 com.microsoft.azure.storage.core.Utility;
+
+import java.util.Locale;
+
+/**
+ * The tier of the block blob on a standard storage account.
+ */
+public enum StandardBlobTier {
+ /**
+ * The tier is not recognized by this version of the library.
+ */
+ UNKNOWN,
+
+ /**
+ * The tier is hot storage.
+ */
+ HOT,
+
+ /**
+ * The tier is cool storage.
+ */
+ COOL,
+
+ /**
+ * The tier is archive storage.
+ */
+ ARCHIVE;
+
+ /**
+ * Parses a standard blob tier from the given string.
+ *
+ * @param standardBlobTierString
+ * A String
which represents the tier of the blob tier on a standard storage account.
+ *
+ * @return A StandardBlobTier
value that represents the standard blob tier.
+ */
+ protected static StandardBlobTier parse(final String standardBlobTierString) {
+ if (Utility.isNullOrEmpty(standardBlobTierString)) {
+ return UNKNOWN;
+ }
+ else if ("hot".equals(standardBlobTierString.toLowerCase(Locale.US))) {
+ return HOT;
+ }
+ else if ("cool".equals(standardBlobTierString.toLowerCase(Locale.US))) {
+ return COOL;
+ }
+ else if ("archive".equals(standardBlobTierString.toLowerCase(Locale.US))) {
+ return ARCHIVE;
+ }
+ else {
+ return UNKNOWN;
+ }
+ }
+}