diff --git a/ChangeLog.txt b/ChangeLog.txt index 0e1283665a48d..082c6b1ee2b99 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,6 @@ +2017.11.01 Version 6.1.0 + * Added support for the last time the tier was modified. + 2017.10.06 Version 6.0.0 * Added support for taking a snapshot of a share. * IOExceptions wrapping StorageExceptions will now contain the StorageException message in the outer exception. diff --git a/README.md b/README.md index df9acf4fa0a06..9639e327af897 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ To get the binaries of this library as distributed by Microsoft, ready for use w com.microsoft.azure azure-storage - 6.0.0 + 6.1.0 ``` diff --git a/microsoft-azure-storage-samples/pom.xml b/microsoft-azure-storage-samples/pom.xml index c697eb4e8dd54..a2e6f197b045a 100644 --- a/microsoft-azure-storage-samples/pom.xml +++ b/microsoft-azure-storage-samples/pom.xml @@ -26,7 +26,7 @@ com.microsoft.azure azure-storage - 6.0.0 + 6.1.0 com.microsoft.azure diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/logging/pom.xml b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/logging/pom.xml index f5c5d85d20a3c..68ade3613ebcb 100644 --- a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/logging/pom.xml +++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/logging/pom.xml @@ -26,7 +26,7 @@ com.microsoft.azure azure-storage - 6.0.0 + 6.1.0 com.microsoft.azure diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java index 3f23ea4780c84..26e4b3431842d 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/AccountSasTests.java @@ -208,14 +208,6 @@ public void testBlobIPAccountSas() throws InvalidKeyException, StorageException, } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } finally { this.blobContainer.deleteIfExists(); @@ -340,14 +332,6 @@ public void testFileIPAccountSas() throws InvalidKeyException, StorageException, } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } finally { this.fileShare.deleteIfExists(); @@ -474,14 +458,6 @@ public void testQueueIPAccountSas() } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } finally { this.queueQueue.deleteIfExists(); @@ -608,14 +584,6 @@ public void testTableIPAccountSas() throws InvalidKeyException, StorageException } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } finally { this.tableTable.deleteIfExists(); 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 579d46b8e6293..978f30359d6b3 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 @@ -1946,22 +1946,38 @@ public void testCloudBlockBlobUploadStandardTier() throws StorageException, IOEx final String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testBlob"); final CloudBlockBlob blob = this.container.getBlockBlobReference(blobName); blob.uploadText("text"); + blob.downloadAttributes(); + assertNotNull(blob.getProperties().getStandardBlobTier()); + assertNull(blob.getProperties().getPremiumPageBlobTier()); + assertTrue(blob.getProperties().isBlobTierInferred()); + + CloudBlockBlob listBlob = (CloudBlockBlob)this.container.listBlobs().iterator().next(); + assertNotNull(listBlob.getProperties().getStandardBlobTier()); + assertNull(listBlob.getProperties().getPremiumPageBlobTier()); + assertTrue(listBlob.getProperties().isBlobTierInferred()); blob.uploadStandardBlobTier(standardBlobTier); assertEquals(standardBlobTier, blob.getProperties().getStandardBlobTier()); assertNull(blob.getProperties().getPremiumPageBlobTier()); assertNull(blob.getProperties().getRehydrationStatus()); + assertFalse(blob.getProperties().isBlobTierInferred()); + assertNull(blob.getProperties().getTierChangeTime()); CloudBlockBlob blob2 = this.container.getBlockBlobReference(blobName); blob2.downloadAttributes(); assertEquals(standardBlobTier, blob2.getProperties().getStandardBlobTier()); assertNull(blob2.getProperties().getPremiumPageBlobTier()); assertNull(blob2.getProperties().getRehydrationStatus()); + assertFalse(blob2.getProperties().isBlobTierInferred()); + assertNotNull(blob2.getProperties().getTierChangeTime()); CloudBlockBlob blob3 = (CloudBlockBlob)this.container.listBlobs().iterator().next(); assertEquals(standardBlobTier, blob3.getProperties().getStandardBlobTier()); assertNull(blob3.getProperties().getPremiumPageBlobTier()); assertNull(blob3.getProperties().getRehydrationStatus()); + assertNull(blob3.getProperties().isBlobTierInferred()); + assertNotNull(blob3.getProperties().getTierChangeTime()); + assertEquals(blob2.getProperties().getTierChangeTime(), blob3.getProperties().getTierChangeTime()); blob.deleteIfExists(); } @@ -1984,32 +2000,38 @@ public void testCloudBlockBlobRehydrateBlob() throws StorageException, IOExcepti assertNull(blobRef1.getProperties().getRehydrationStatus()); assertEquals(StandardBlobTier.ARCHIVE, blobRef1.getProperties().getStandardBlobTier()); assertNull(blobRef1.getProperties().getPremiumPageBlobTier()); + assertNull(blobRef1.getProperties().getTierChangeTime()); blob.downloadAttributes(); assertEquals(RehydrationStatus.PENDING_TO_COOL, blob.getProperties().getRehydrationStatus()); assertEquals(StandardBlobTier.ARCHIVE, blob.getProperties().getStandardBlobTier()); assertNull(blob.getProperties().getPremiumPageBlobTier()); + assertNotNull(blob.getProperties().getTierChangeTime()); CloudBlockBlob blobRef2 = this.container.getBlockBlobReference(blobName2); blobRef2.uploadStandardBlobTier(StandardBlobTier.HOT); assertNull(blobRef2.getProperties().getRehydrationStatus()); assertEquals(StandardBlobTier.ARCHIVE, blobRef2.getProperties().getStandardBlobTier()); assertNull(blobRef2.getProperties().getPremiumPageBlobTier()); + assertNull(blobRef2.getProperties().getTierChangeTime()); blob2.downloadAttributes(); assertEquals(RehydrationStatus.PENDING_TO_HOT, blob2.getProperties().getRehydrationStatus()); assertEquals(StandardBlobTier.ARCHIVE, blob2.getProperties().getStandardBlobTier()); assertNull(blob2.getProperties().getPremiumPageBlobTier()); + assertNotNull(blob2.getProperties().getTierChangeTime()); 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()); + assertNotNull(listBlob.getProperties().getTierChangeTime()); CloudBlockBlob listBlob2 = (CloudBlockBlob)it.next(); assertEquals(RehydrationStatus.PENDING_TO_HOT, listBlob2.getProperties().getRehydrationStatus()); assertEquals(StandardBlobTier.ARCHIVE, listBlob2.getProperties().getStandardBlobTier()); assertNull(listBlob2.getProperties().getPremiumPageBlobTier()); + assertNotNull(listBlob2.getProperties().getTierChangeTime()); } } 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 6ade1eb60b60e..f6fa2cdc0e395 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 @@ -1252,7 +1252,7 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept CloudPageBlob blob2 = container.getPageBlobReference(blobName); blob2.downloadAttributes(); assertEquals(PremiumPageBlobTier.P4, blob2.getProperties().getPremiumPageBlobTier()); - assertNull(blob2.getProperties().isBlobTierInferred()); + assertFalse(blob2.getProperties().isBlobTierInferred()); assertNull(blob2.getProperties().getStandardBlobTier()); assertNull(blob2.getProperties().getRehydrationStatus()); @@ -1268,7 +1268,7 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept CloudPageBlob blob3Ref = container.getPageBlobReference("blob3"); blob3Ref.downloadAttributes(); assertEquals(PremiumPageBlobTier.P6, blob3Ref.getProperties().getPremiumPageBlobTier()); - assertNull(blob3Ref.getProperties().isBlobTierInferred()); + assertFalse(blob3Ref.getProperties().isBlobTierInferred()); // Test upload from stream API ByteArrayInputStream srcStream = new ByteArrayInputStream(buffer); @@ -1282,7 +1282,7 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept CloudPageBlob blob4Ref = container.getPageBlobReference("blob4"); blob4Ref.downloadAttributes(); assertEquals(PremiumPageBlobTier.P10, blob4Ref.getProperties().getPremiumPageBlobTier()); - assertNull(blob4Ref.getProperties().isBlobTierInferred()); + assertFalse(blob4Ref.getProperties().isBlobTierInferred()); // Test upload from file API File sourceFile = File.createTempFile("sourceFile", ".tmp"); @@ -1301,7 +1301,7 @@ public void testCloudPageBlobSetPremiumBlobTierOnCreate() throws URISyntaxExcept CloudPageBlob blob5Ref = container.getPageBlobReference("blob5"); blob5Ref.downloadAttributes(); assertEquals(PremiumPageBlobTier.P20, blob5Ref.getProperties().getPremiumPageBlobTier()); - assertNull(blob5Ref.getProperties().isBlobTierInferred()); + assertFalse(blob5Ref.getProperties().isBlobTierInferred()); } finally { container.deleteIfExists(); @@ -1318,6 +1318,10 @@ public void testCloudPageBlobSetBlobTier() throws URISyntaxException, StorageExc CloudPageBlob blob = container.getPageBlobReference(blobName); blob.create(1024); assertNull(blob.getProperties().isBlobTierInferred()); + CloudPageBlob listBlob = (CloudPageBlob)container.listBlobs().iterator().next(); + assertNull(listBlob.getProperties().getStandardBlobTier()); + assertNotNull(listBlob.getProperties().getPremiumPageBlobTier()); + blob.downloadAttributes(); assertTrue(blob.getProperties().isBlobTierInferred()); assertEquals(PremiumPageBlobTier.P10, blob.getProperties().getPremiumPageBlobTier()); @@ -1331,7 +1335,7 @@ public void testCloudPageBlobSetBlobTier() throws URISyntaxException, StorageExc CloudPageBlob blob2 = container.getPageBlobReference(blobName); blob2.downloadAttributes(); assertEquals(PremiumPageBlobTier.P40, blob2.properties.getPremiumPageBlobTier()); - assertNull(blob2.getProperties().isBlobTierInferred()); + assertFalse(blob2.getProperties().isBlobTierInferred()); boolean pageBlobWithTierFound = false; for (ListBlobItem blobItem : container.listBlobs()) { @@ -1404,7 +1408,7 @@ public void testCloudPageBlobSetBlobTierOnCopy() throws URISyntaxException, Stor CloudPageBlob copyRef = container.getPageBlobReference("copy"); copyRef.downloadAttributes(); assertEquals(PremiumPageBlobTier.P30, copyRef.getProperties().getPremiumPageBlobTier()); - assertNull(copyRef.getProperties().isBlobTierInferred()); + assertFalse(copyRef.getProperties().isBlobTierInferred()); // copy where source does not have a tier CloudPageBlob source2 = container.getPageBlobReference("source2"); diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java index bcf0b47cad022..33c05ec26979d 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java @@ -137,14 +137,6 @@ public void testIpAcl() } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } // Ensure access attempt from the single allowed IP succeeds diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java index 3cd0ef7248579..2eec550c97684 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/file/FileSasTests.java @@ -181,14 +181,6 @@ public void testIpAcl() } catch (StorageException ex) { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, ex.getHttpStatusCode()); - - final String[] words = ex.getMessage().split(" "); - // final word - String lastWord = words[words.length - 1]; - // strip trailing period - lastWord = lastWord.substring(0, lastWord.length() - 1); - - sourceIP = new IPRange(lastWord); } // Ensure access attempt from the single allowed IP succeeds 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 69d063316a2b8..69d0d52124991 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/Constants.java @@ -661,7 +661,7 @@ public static class HeaderConstants { /** * Specifies the value to use for UserAgent header. */ - public static final String USER_AGENT_VERSION = "6.0.0"; + public static final String USER_AGENT_VERSION = "6.1.0"; /** * The default type for content-type and accept @@ -899,6 +899,16 @@ public static class QueryConstants { */ public static final String ACCESS_TIER = "AccessTier"; + /** + * XML element for the access tier change time. + */ + public static final String ACCESS_TIER_CHANGE_TIME = "AccessTierChangeTime"; + + /** + * XML element for access if the access tier is inferred. + */ + public static final String ACCESS_TIER_INFERRED = "AccessTierInferred"; + /** * XML element for the archive status. */ 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 102bbd4bdc974..5f97fb7e55d70 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 @@ -20,6 +20,10 @@ * Holds the Constants used for the Blob Service. */ final class BlobConstants { + /** + * The header that specifies the last time the tier was modified. + */ + public static final String ACCESS_TIER_CHANGE_TIME_HEADER = Constants.PREFIX_FOR_STORAGE_HEADER + "access-tier-change-time"; /** * The header that specifies the access tier header. 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 5fe51e3f866ae..220a2cb528d28 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 @@ -19,6 +19,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; +import java.util.Date; import java.util.HashMap; import java.util.Stack; @@ -348,6 +349,12 @@ else if (!standardBlobTier.equals(StandardBlobTier.UNKNOWN)) { } } } + else if (Constants.ACCESS_TIER_INFERRED.equals(currentNode)) { + this.properties.setBlobTierInferred(Boolean.parseBoolean(value)); + } + else if (Constants.ACCESS_TIER_CHANGE_TIME.equals(currentNode)) { + this.properties.setTierChangeTime(Utility.parseRFC1123DateFromStringInGMT(value)); + } else if (Constants.ARCHIVE_STATUS.equals(currentNode)) { this.properties.setRehydrationStatus(RehydrationStatus.parse(value)); } 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 3c645e3a4ce87..c336452d137b8 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 @@ -132,6 +132,11 @@ public final class BlobProperties { */ private Boolean isBlobTierInferredTier; + /** + * Represents the last time the tier was changed. + */ + private Date tierChangeTime; + /** * Represents the rehydration status if the blob is being rehydrated. */ @@ -174,6 +179,7 @@ public BlobProperties(final BlobProperties other) { this.serverEncrypted = other.serverEncrypted; this.standardBlobTier = other.standardBlobTier; this.rehydrationStatus = other.rehydrationStatus; + this.tierChangeTime = other.tierChangeTime; } /** @@ -296,12 +302,19 @@ public Date getLastModified() { } /** - * Gets a value indicating if the tier of the premium page blob has been inferred. + * Gets a value indicating if the tier of the blob has been inferred. * * @return A {@Link java.lang.Boolean} object which represents if the blob tier was inferred. */ public Boolean isBlobTierInferred() { return this.isBlobTierInferredTier; } + /** + * Gets a value indicating the last time the tier was changed on the blob. + * + * @return A {@link java.util.Date} object which represents the last time the tier was changed. + */ + public Date getTierChangeTime() { return this.tierChangeTime; } + /** * Gets the lease status for the blob. * @@ -596,6 +609,15 @@ protected void setBlobTierInferred(Boolean isBlobTierInferredTier) { this.isBlobTierInferredTier = isBlobTierInferredTier; } + /** + * Sets the last time the tier was modified on the blob. + * @param tierChangeTime + * A {@link java.util.Date} which specifies the last time the tier was modified. + */ + protected void setTierChangeTime(Date tierChangeTime) { + this.tierChangeTime = tierChangeTime; + } + /** * Sets the rehydration status of the blob. * @param rehydrationStatus 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 70b38e691c5fe..33ff7c38743cb 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 @@ -154,6 +154,9 @@ else if (!standardBlobTier.equals(StandardBlobTier.UNKNOWN)) { if (!Utility.isNullOrEmpty(tierInferredString)) { properties.setBlobTierInferred(Boolean.parseBoolean(tierInferredString)); } + else if (properties.getPremiumPageBlobTier() != null || properties.getStandardBlobTier() != null) { + properties.setBlobTierInferred(false); + } final String rehydrationStatusString = request.getHeaderField(BlobConstants.ARCHIVE_STATUS_HEADER); if (!Utility.isNullOrEmpty(rehydrationStatusString)) { @@ -164,6 +167,11 @@ else if (!standardBlobTier.equals(StandardBlobTier.UNKNOWN)) { properties.setRehydrationStatus(null); } + final long tierChangeTime = request.getHeaderFieldDate(BlobConstants.ACCESS_TIER_CHANGE_TIME_HEADER, 0); + if (tierChangeTime != 0) { + properties.setTierChangeTime(new Date(tierChangeTime)); + } + final String incrementalCopyHeaderString = request.getHeaderField(Constants.HeaderConstants.INCREMENTAL_COPY); if (!Utility.isNullOrEmpty(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 4e5926ede8ae6..e867f7637301d 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 @@ -2626,7 +2626,9 @@ public Void preProcessResponse(CloudBlob blob, CloudBlobClient client, Operation 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); diff --git a/pom.xml b/pom.xml index 8aa563d667a22..9fb89b9445d0f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.microsoft.azure azure-storage - 6.0.0 + 6.1.0 jar Microsoft Azure Storage Client SDK