diff --git a/ChangeLog.txt b/ChangeLog.txt index 8fe478e4a635c..2c15b781280a6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,8 +1,22 @@ -2013.1.18 Version 0.4.0 +2013.03.12 Version 0.4.1 + * Added "Azure-SDK-For-Java/" To User-Agent HTTP header + * Added connection string support for Service Bus + * Added new methods to break lease for Storage Blob which doesn't require a lease id and returns the result as an object. Deprecated the old breakLease() methods. + * Added a new method to get the historical events for Media Services + * Fixed Storage Table encoding issue for special characters + * BlobOutputStream now commits block list using LATEST instead of UNCOMMITTED + * Added RequestResult to StorageEvents + * Fixed issue when accessing OperationContext RequestResults + * Fixed the return value of BlobInputStream.read + * Fixed CloudPageBlob.downloadPageRanges to retrieve the blob length + * Fixed MD5 validation in BlobInputStream + * Return ETag in TableResult not only for Insert but also for other operations + +2013.01.18 Version 0.4.0 * Added support for Windows Azure Media Services * Updated dependencies to non-beta stable versions - * Add a Sending Request Event to OperationContext in Storage Client code - * Fix a bug in the STorage client in blob download resume for blobs greater than 2GB + * Added a Sending Request Event to OperationContext in Storage Client code + * Fixed a bug in the Storage client in blob download resume for blobs greater than 2GB 2012.10.29 Version 0.3.3 * In the blob client, fixed a bug which allows users to call write APIs on a blob snapshot reference diff --git a/README.md b/README.md index ff2c5d7242be9..22ab0a06a9ece 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ within your project you can also have them installed by the Java package manager com.microsoft.windowsazure microsoft-windowsazure-api - 0.4.0 + 0.4.1 ##Minimum Requirements diff --git a/microsoft-azure-api/pom.xml b/microsoft-azure-api/pom.xml index c2ae959ce9d90..1900ba335e498 100644 --- a/microsoft-azure-api/pom.xml +++ b/microsoft-azure-api/pom.xml @@ -17,7 +17,7 @@ 4.0.0 com.microsoft.windowsazure microsoft-windowsazure-api - 0.4.0 + 0.4.1 jar Microsoft Windows Azure Client API diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobInputStream.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobInputStream.java index a31526a40e008..ac68dc7e15e96 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobInputStream.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobInputStream.java @@ -82,6 +82,11 @@ public final class BlobInputStream extends InputStream { */ private boolean validateBlobMd5; + /** + * Holds the Blob MD5. + */ + private final String retrievedContentMD5Value; + /** * Holds the reference to the current buffered data. */ @@ -161,11 +166,11 @@ protected BlobInputStream(final CloudBlob parentBlob, final AccessCondition acce final HttpURLConnection attributesRequest = this.opContext.getCurrentRequestObject(); - final String retrievedContentMD5Value = attributesRequest.getHeaderField(Constants.HeaderConstants.CONTENT_MD5); + this.retrievedContentMD5Value = attributesRequest.getHeaderField(Constants.HeaderConstants.CONTENT_MD5); // Will validate it if it was returned this.validateBlobMd5 = !options.getDisableContentMD5Validation() - && !Utility.isNullOrEmpty(retrievedContentMD5Value); + && !Utility.isNullOrEmpty(this.retrievedContentMD5Value); // Validates the first option, and sets future requests to use if match // request option. @@ -395,8 +400,17 @@ public boolean markSupported() { @DoesServiceRequest public int read() throws IOException { final byte[] tBuff = new byte[1]; - this.read(tBuff, 0, 1); - return tBuff[0]; + final int numberOfBytesRead = this.read(tBuff, 0, 1); + + if (numberOfBytesRead > 0) { + return tBuff[0] & 0xFF; + } + else if (numberOfBytesRead == 0) { + throw new IOException("Unexpected error. Stream returned unexpected number of bytes."); + } + else { + return -1; + } } /** @@ -519,13 +533,13 @@ private synchronized int readInternal(final byte[] b, final int off, int len) th if (this.currentAbsoluteReadPosition == this.streamLength) { // Reached end of stream, validate md5. final String calculatedMd5 = Base64.encode(this.md5Digest.digest()); - if (!calculatedMd5.equals(this.parentBlobRef.getProperties().getContentMD5())) { + if (!calculatedMd5.equals(this.retrievedContentMD5Value)) { this.lastError = Utility .initIOException(new StorageException( StorageErrorCodeStrings.INVALID_MD5, String.format( "Blob data corrupted (integrity check failed), Expected value is %s, retrieved %s", - this.parentBlobRef.getProperties().getContentMD5(), calculatedMd5), + this.retrievedContentMD5Value, calculatedMd5), Constants.HeaderConstants.HTTP_UNUSED_306, null, null)); this.streamFaulted = true; throw this.lastError; diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobOutputStream.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobOutputStream.java index dae6409998617..93d870b15e1bf 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobOutputStream.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/BlobOutputStream.java @@ -356,7 +356,7 @@ private synchronized void dispatchWrite(final int writeLength) throws IOExceptio if (this.streamType == BlobType.BLOCK_BLOB) { final CloudBlockBlob blobRef = (CloudBlockBlob) this.parentBlobRef; final String blockID = Base64.encode(Utility.getBytesFromLong(this.blockIdSequenceNumber++)); - this.blockList.add(new BlockEntry(blockID, BlockSearchMode.UNCOMMITTED)); + this.blockList.add(new BlockEntry(blockID, BlockSearchMode.LATEST)); worker = new Callable() { @Override diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java index 585c5cb8da14d..84e345591cc55 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlob.java @@ -221,7 +221,7 @@ protected CloudBlob(final CloudBlob otherBlob) { * * @param leaseTimeInSeconds * Specifies the span of time for which to acquire the lease, in seconds. - * If null, an infinite lease will be acquired. If not null, the value must be greater than + * If null, an infinite lease will be acquired. If not null, the value must be greater than * zero. * * @param proposedLeaseId @@ -245,7 +245,7 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String * * @param leaseTimeInSeconds * Specifies the span of time for which to acquire the lease, in seconds. - * If null, an infinite lease will be acquired. If not null, the value must be greater than + * If null, an infinite lease will be acquired. If not null, the value must be greater than * zero. * * @param proposedLeaseId @@ -254,12 +254,12 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String * * @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 + * 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. The context * is used to track requests to the storage service, and to provide additional runtime information about @@ -298,7 +298,7 @@ public String execute(final CloudBlobClient client, final CloudBlob blob, final client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -342,7 +342,7 @@ protected final void assertCorrectBlobType() throws StorageException { } /** - * Breaks the lease and ensures that another client cannot acquire a new lease until the current lease period + * Breaks the lease and ensures that another client cannot acquire a new lease until the current lease period * has expired. * * @param breakPeriodInSeconds @@ -360,7 +360,7 @@ public final long breakLease(final Integer breakPeriodInSeconds) throws StorageE } /** - * Breaks the existing lease, using the specified request options and operation context, and ensures that another + * Breaks the existing lease, using the specified request options and operation context, and ensures that another * client cannot acquire a new lease until the current lease period has expired. * * @param breakPeriodInSeconds @@ -371,7 +371,7 @@ public final long breakLease(final Integer breakPeriodInSeconds) throws StorageE * 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 + * 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. The context @@ -410,7 +410,7 @@ public Long execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -544,7 +544,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op BlobRequest.addMetadata(request, blob.metadata, opContext); client.getCredentials().signRequest(request, 0); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -623,7 +623,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -698,7 +698,7 @@ public CloudBlob execute(final CloudBlobClient client, final CloudBlob blob, client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -787,7 +787,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -878,7 +878,7 @@ public Boolean execute(final CloudBlobClient client, final CloudBlob blob, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_ACCEPTED) { return true; @@ -961,8 +961,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op blobOptions.getTimeoutIntervalInMs(), blob.snapshotID, accessCondition, blobOptions, opContext); client.getCredentials().signRequest(request, -1L); - final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext); - this.setResult(opContext.getLastResult()); + final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext, this.getResult()); final String contentMD5 = request.getHeaderField(Constants.HeaderConstants.CONTENT_MD5); final Boolean validateMD5 = !blobOptions.getDisableContentMD5Validation() @@ -1015,8 +1014,8 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op if ((ex.getHttpStatusCode() == Constants.HeaderConstants.HTTP_UNUSED_306 && !ex.getErrorCode().equals( StorageErrorCodeStrings.OUT_OF_RANGE_INPUT)) || ex.getHttpStatusCode() == HttpURLConnection.HTTP_PRECON_FAILED - || !dummyPolicy.shouldRetry(0, opContext.getLastResult().getStatusCode(), - (Exception) ex.getCause(), opContext).isShouldRetry()) { + || !dummyPolicy.shouldRetry(0, impl.getResult().getStatusCode(), (Exception) ex.getCause(), + opContext).isShouldRetry()) { opContext.setIntermediateMD5(null); throw ex; } @@ -1141,7 +1140,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1298,8 +1297,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, -1L); - final InputStream sourceStream = ExecutionEngine.getInputStream(request, opContext); - this.setResult(opContext.getLastResult()); + final InputStream sourceStream = ExecutionEngine.getInputStream(request, opContext, this.getResult()); int totalRead = 0; int nextRead = buffer.length - bufferOffset; @@ -1328,14 +1326,16 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op return null; } - // Do not update blob length in downloadRangeInternal API. - final long orignalBlobLength = blob.properties.getLength(); + // Do not update blob length and Content-MD5 in downloadRangeInternal API. + final long originalBlobLength = blob.properties.getLength(); + final String originalContentMD5 = blob.properties.getContentMD5(); final BlobAttributes retrievedAttributes = BlobResponse.getAttributes(request, blob.getUri(), blob.snapshotID, opContext); blob.properties = retrievedAttributes.getProperties(); blob.metadata = retrievedAttributes.getMetadata(); blob.copyState = retrievedAttributes.getCopyState(); - blob.properties.setLength(orignalBlobLength); + blob.properties.setContentMD5(originalContentMD5); + blob.properties.setLength(originalBlobLength); final String contentLength = request.getHeaderField(Constants.HeaderConstants.CONTENT_LENGTH); final long expectedLength = Long.parseLong(contentLength); @@ -1433,7 +1433,7 @@ public Boolean execute(final CloudBlobClient client, final CloudBlob blob, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { final BlobAttributes retrievedAttributes = BlobResponse.getAttributes(request, blob.getUri(), @@ -1920,7 +1920,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -2000,7 +2000,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -2049,7 +2049,7 @@ public final void changeLease(final String proposedLeaseId, final AccessConditio * required to be set with an access condition. * @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 + * 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. The context @@ -2089,7 +2089,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -2216,7 +2216,7 @@ public Long execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_CONFLICT) { final StorageException potentialConflictException = StorageException.translateException(request, @@ -2366,7 +2366,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op HttpURLConnection.HTTP_FORBIDDEN, null, null); } - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -2440,7 +2440,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op BlobRequest.addMetadata(request, blob.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -2514,7 +2514,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op BlobRequest.addMetadata(request, blob.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java index 181549a8d5750..c000b97c98edc 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobClient.java @@ -388,7 +388,7 @@ ResultSegment listContainersCore(final String prefix, this.getCredentials().signRequest(listContainerRequest, -1L); - taskReference.setResult(ExecutionEngine.processRequest(listContainerRequest, opContext)); + ExecutionEngine.processRequest(listContainerRequest, opContext, taskReference.getResult()); if (taskReference.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { taskReference.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java index ff67b888bfe33..b1d1a7a6c8db1 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainer.java @@ -224,7 +224,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta ContainerRequest.addMetadata(request, container.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -298,7 +298,7 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co ContainerRequest.addMetadata(request, container.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); // Validate response code here if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_CREATED) { @@ -390,7 +390,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -460,7 +460,7 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_ACCEPTED) { container.updatePropertiesFromResponse(request); @@ -533,7 +533,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -610,7 +610,7 @@ public BlobContainerPermissions execute(final CloudBlobClient client, final Clou client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -689,7 +689,7 @@ public Boolean execute(final CloudBlobClient client, final CloudBlobContainer co client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { container.updatePropertiesFromResponse(request); @@ -1108,7 +1108,7 @@ ResultSegment listBlobsCore(final String prefix, final boolean use this.blobServiceClient.getCredentials().signRequest(listBlobsRequest, -1L); - taskReference.setResult(ExecutionEngine.processRequest(listBlobsRequest, opContext)); + ExecutionEngine.processRequest(listBlobsRequest, opContext, taskReference.getResult()); if (taskReference.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { taskReference.setNonExceptionedRetryableFailure(true); @@ -1533,7 +1533,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta ContainerRequest.addMetadata(request, container.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1613,7 +1613,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1633,7 +1633,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta * * @param leaseTimeInSeconds * Specifies the span of time for which to acquire the lease, in seconds. - * If null, an infinite lease will be acquired. If not null, the value must be greater than + * If null, an infinite lease will be acquired. If not null, the value must be greater than * zero. * * @param proposedLeaseId @@ -1657,7 +1657,7 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String * * @param leaseTimeInSeconds * Specifies the span of time for which to acquire the lease, in seconds. - * If null, an infinite lease will be acquired. If not null, the value must be greater than + * If null, an infinite lease will be acquired. If not null, the value must be greater than * zero. * * @param proposedLeaseId @@ -1666,12 +1666,12 @@ public final String acquireLease(final Integer leaseTimeInSeconds, final String * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the container. - * + * * @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 + * 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. The context * is used to track requests to the storage service, and to provide additional runtime information about @@ -1710,7 +1710,7 @@ public String execute(final CloudBlobClient client, final CloudBlobContainer con client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -1731,8 +1731,8 @@ public String execute(final CloudBlobClient client, final CloudBlobContainer con * Renews an existing lease with the specified access conditions. * * @param accessCondition - * An {@link AccessCondition} object that represents the access conditions for the container. The lease ID is - * required to be set with an access condition. + * An {@link AccessCondition} object that represents the access conditions for the container. The lease + * ID is required to be set with an access condition. * * @throws StorageException * If a storage service error occurred. @@ -1748,12 +1748,12 @@ public final void renewLease(final AccessCondition accessCondition) throws Stora * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the blob. The lease ID is * required to be set with an access condition. - * + * * @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 + * 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. The context * is used to track requests to the storage service, and to provide additional runtime information about @@ -1792,7 +1792,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1824,17 +1824,18 @@ public final void releaseLease(final AccessCondition accessCondition) throws Sto } /** - * Releases the lease on the container using the specified access conditions, request options, and operation context. + * Releases the lease on the container using the specified access conditions, request options, and operation + * context. * * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the blob. The lease ID is * required to be set with an access condition. - * + * * @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 + * 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. The context * is used to track requests to the storage service, and to provide additional runtime information about @@ -1873,7 +1874,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1890,7 +1891,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta } /** - * Breaks the lease and ensures that another client cannot acquire a new lease until the current lease + * Breaks the lease and ensures that another client cannot acquire a new lease until the current lease * period has expired. * * @param breakPeriodInSeconds @@ -1908,7 +1909,7 @@ public final long breakLease(final Integer breakPeriodInSeconds) throws StorageE } /** - * Breaks the existing lease, using the specified request options and operation context, and ensures that + * Breaks the existing lease, using the specified request options and operation context, and ensures that * another client cannot acquire a new lease until the current lease period has expired. * * @param breakPeriodInSeconds @@ -1919,7 +1920,7 @@ public final long breakLease(final Integer breakPeriodInSeconds) throws StorageE * 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 + * 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. The context @@ -1958,7 +1959,7 @@ public Long execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); @@ -2006,12 +2007,12 @@ public final void changeLease(final String proposedLeaseId, final AccessConditio * @param accessCondition * An {@link AccessCondition} object that represents the access conditions for the blob. The lease ID is * required to be set with an access condition. - * + * * @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 + * 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. The context * is used to track requests to the storage service, and to provide additional runtime information about @@ -2050,7 +2051,7 @@ public Void execute(final CloudBlobClient client, final CloudBlobContainer conta client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java index b28a54a6affd6..9ee73d83c1d15 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudBlockBlob.java @@ -204,7 +204,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op Utility.writeToOutputStream(blockListInputStream, request.getOutputStream(), descriptor.getLength(), false, false, null, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -293,7 +293,7 @@ public ArrayList execute(final CloudBlobClient client, final CloudBl client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -624,7 +624,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op Utility.writeToOutputStream(sourceStream, request.getOutputStream(), length, true /* rewindSourceStream */, false /* calculateMD5 */, null, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java index e31eb5aff1961..d81af25c62672 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/client/CloudPageBlob.java @@ -272,7 +272,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -352,7 +352,7 @@ public ArrayList execute(final CloudBlobClient client, final CloudBlo client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -360,6 +360,8 @@ public ArrayList execute(final CloudBlobClient client, final CloudBlo } blob.updateEtagAndLastModifiedFromResponse(request); + blob.updateLengthFromResponse(request); + final GetPageRangesResponse response = new GetPageRangesResponse(request.getInputStream()); return response.getPageRanges(); } @@ -482,7 +484,7 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op client.getCredentials().signRequest(request, 0L); } - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -490,7 +492,6 @@ public Void execute(final CloudBlobClient client, final CloudBlob blob, final Op } blob.updateEtagAndLastModifiedFromResponse(request); - blob.updateLengthFromResponse(request); return null; } }; diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/Constants.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/Constants.java index 021acc7a3ad8b..baea2ec847207 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/Constants.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/Constants.java @@ -327,7 +327,7 @@ public static class HeaderConstants { /** * Specifies the value to use for UserAgent header. */ - public static final String USER_AGENT_VERSION = "Client v0.1.3.1"; + public static final String USER_AGENT_VERSION = "Client v0.1.3.2"; } /** diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/OperationContext.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/OperationContext.java index 7e6e3a3320dae..d19a8eba6b649 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/OperationContext.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/OperationContext.java @@ -51,7 +51,7 @@ public final class OperationContext { * Represents request results, in the form of an ArrayList object that contains the * {@link RequestResult} objects, for each physical request that is made. */ - private ArrayList requestResults; + private final ArrayList requestResults; /** * Represents an event that is triggered before sending a request. @@ -135,7 +135,7 @@ public MessageDigest getIntermediateMD5() { * * @return A {@link RequestResult} object that represents the last request result. */ - public RequestResult getLastResult() { + public synchronized RequestResult getLastResult() { if (this.requestResults == null || this.requestResults.size() == 0) { return null; } @@ -165,6 +165,16 @@ public ArrayList getRequestResults() { return this.requestResults; } + /** + * Reserved for internal use. appends a {@link RequestResult} object to the internal collection in a synchronized + * manner. + * + * @param requestResult + */ + public synchronized void appendRequestResult(RequestResult requestResult) { + this.requestResults.add(requestResult); + } + /** * @return the SendingRequestEvent */ diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ResponseReceivedEvent.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ResponseReceivedEvent.java index f0b8419d1ab5b..bf1506495a5db 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ResponseReceivedEvent.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ResponseReceivedEvent.java @@ -23,13 +23,18 @@ public final class ResponseReceivedEvent { * Represents a connection object. Currently only java.net.HttpURLConnection is supported as a * connection object. */ - private Object connectionObject; + private final Object connectionObject; /** * Represents a 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. */ - private OperationContext opContext; + private final OperationContext opContext; + + /** + * A {@link RequestResult} object that represents the last request result. + */ + private final RequestResult requestResult; /** * Creates an instance of the ResponseReceivedEvent class. @@ -41,10 +46,14 @@ public final class ResponseReceivedEvent { * @param connectionObject * Represents a connection object. Currently only java.net.HttpURLConnection is supported as * a connection object. + * @param requestResult + * A {@link RequestResult} object that represents the current request result. */ - public ResponseReceivedEvent(final OperationContext opContext, final Object connectionObject) { + public ResponseReceivedEvent(final OperationContext opContext, final Object connectionObject, + final RequestResult requestResult) { this.opContext = opContext; this.connectionObject = connectionObject; + this.requestResult = requestResult; } /** @@ -60,4 +69,11 @@ public Object getConnectionObject() { public OperationContext getOpContext() { return this.opContext; } + + /** + * @return A {@link RequestResult} object that represents the current request result. + */ + public RequestResult getRequestResult() { + return this.requestResult; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/SendingRequestEvent.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/SendingRequestEvent.java index 8b61f7e092ff9..8d0e6da594d66 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/SendingRequestEvent.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/SendingRequestEvent.java @@ -31,6 +31,11 @@ public final class SendingRequestEvent { */ private final OperationContext opContext; + /** + * A {@link RequestResult} object that represents the last request result. + */ + private final RequestResult requestResult; + /** * Creates an instance of the SendingRequestEvent class. * @@ -41,10 +46,14 @@ public final class SendingRequestEvent { * @param connectionObject * Represents a connection object. Currently only java.net.HttpURLConnection is supported as * a connection object. + * @param requestResult + * A {@link RequestResult} object that represents the current request result. */ - public SendingRequestEvent(final OperationContext opContext, final Object connectionObject) { + public SendingRequestEvent(final OperationContext opContext, final Object connectionObject, + final RequestResult requestResult) { this.opContext = opContext; this.connectionObject = connectionObject; + this.requestResult = requestResult; } /** @@ -60,4 +69,11 @@ public Object getConnectionObject() { public OperationContext getOpContext() { return this.opContext; } + + /** + * @return A {@link RequestResult} object that represents the current request result. + */ + public RequestResult getRequestResult() { + return this.requestResult; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java index 02f0322b2808d..8a6df9f916f3e 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/ServiceClient.java @@ -144,7 +144,7 @@ public ServiceProperties execute(final ServiceClient client, final Void v, final .getRequestOptions().getTimeoutIntervalInMs(), null, opContext); client.getCredentials().signRequest(request, -1); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -242,13 +242,13 @@ public void setRetryPolicyFactory(final RetryPolicyFactory retryPolicyFactory) { /** * Sets the timeout to use when making requests to the storage service. *

- * 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 + * 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. * - * The default timeout interval for a request made via the service client is 90 seconds. 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 + * The default timeout interval for a request made via the service client is 90 seconds. 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#timeoutIntervalInMs} property. * * If you are downloading a large blob, you should increase the value of the timeout beyond the default value. @@ -330,7 +330,7 @@ public Void execute(final ServiceClient client, final Void v, final OperationCon Utility.writeToOutputStream(dataInputStream, request.getOutputStream(), descriptor.getLength(), false /* rewindSourceStream */, false /* calculateMD5 */, null, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_ACCEPTED) { this.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java index ba188fb376928..9d3ad41e569ab 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/ExecutionEngine.java @@ -106,7 +106,7 @@ public static RESULT_TYPE executeWithRet while (true) { try { // reset result flags - task.initialize(); + task.initialize(opContext); final RESULT_TYPE result = task.execute(client, parentObject, opContext); @@ -119,7 +119,7 @@ public static RESULT_TYPE executeWithRet else { // The task may have already parsed an exception. translatedException = task.materializeException(getLastRequestObject(opContext), opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); // throw on non retryable status codes: 501, 505, blob type // mismatch @@ -134,45 +134,45 @@ public static RESULT_TYPE executeWithRet // Retryable translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); } catch (final SocketTimeoutException e) { // Retryable translatedException = new StorageException(StorageErrorCodeStrings.OPERATION_TIMED_OUT, "The operation did not complete in the specified time.", -1, null, e); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); } catch (final IOException e) { // Retryable translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); } catch (final XMLStreamException e) { // Non Retryable, just throw translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); throw translatedException; } catch (final InvalidKeyException e) { // Non Retryable, just throw translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); throw translatedException; } catch (final URISyntaxException e) { // Non Retryable, just throw translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); throw translatedException; } catch (final TableServiceException e) { task.getResult().setStatusCode(e.getHttpStatusCode()); task.getResult().setStatusMessage(e.getMessage()); - setLastException(opContext, e); + task.getResult().setException(e); if (!e.isRetryable()) { throw e; } @@ -183,20 +183,20 @@ public static RESULT_TYPE executeWithRet catch (final StorageException e) { // Non Retryable, just throw // do not translate StorageException - setLastException(opContext, e); + task.getResult().setException(e); throw e; } catch (final Exception e) { // Non Retryable, just throw translatedException = StorageException .translateException(getLastRequestObject(opContext), e, opContext); - setLastException(opContext, translatedException); + task.getResult().setException(translatedException); throw translatedException; } // Evaluate Retry Policy - retryRes = policy.shouldRetry(currentRetryCount, task.getResult().getStatusCode(), opContext - .getLastResult().getException(), opContext); + retryRes = policy.shouldRetry(currentRetryCount, task.getResult().getStatusCode(), task.getResult() + .getException(), opContext); if (!retryRes.isShouldRetry()) { throw translatedException; } @@ -214,19 +214,21 @@ public static RESULT_TYPE executeWithRet * the request to process * @param opContext * an object used to track the execution of the operation + * @param currResult + * A {@link RequestResult} object that represents the current request result. * @return the input stream from the request * @throws IOException * if there is an error making the connection */ - public static InputStream getInputStream(final HttpURLConnection request, final OperationContext opContext) - throws IOException { - final RequestResult currResult = new RequestResult(); + public static InputStream getInputStream(final HttpURLConnection request, final OperationContext opContext, + final RequestResult currResult) throws IOException { + opContext.setCurrentRequestObject(request); currResult.setStartDate(new Date()); - opContext.getRequestResults().add(currResult); if (opContext.getSendingRequestEventHandler().hasListeners()) { - opContext.getSendingRequestEventHandler().fireEvent(new SendingRequestEvent(opContext, request)); + opContext.getSendingRequestEventHandler() + .fireEvent(new SendingRequestEvent(opContext, request, currResult)); } try { @@ -278,7 +280,8 @@ public static void getResponseCode(final RequestResult currResult, final HttpURL currResult.setContentMD5(BaseResponse.getContentMD5(request)); if (opContext.getResponseReceivedEventHandler().hasListeners()) { - opContext.getResponseReceivedEventHandler().fireEvent(new ResponseReceivedEvent(opContext, request)); + opContext.getResponseReceivedEventHandler().fireEvent( + new ResponseReceivedEvent(opContext, request, currResult)); } } @@ -290,19 +293,20 @@ public static void getResponseCode(final RequestResult currResult, final HttpURL * the request to process * @param opContext * an object used to track the execution of the operation - * @return a RequestResult object representing the status code/ message of the current request + * @param currResult + * A {@link RequestResult} object that represents the current request result. * @throws IOException * if there is an error making the connection */ - public static RequestResult processRequest(final HttpURLConnection request, final OperationContext opContext) - throws IOException { - final RequestResult currResult = new RequestResult(); - currResult.setStartDate(new Date()); - opContext.getRequestResults().add(currResult); + public static void processRequest(final HttpURLConnection request, final OperationContext opContext, + final RequestResult currResult) throws IOException { + opContext.setCurrentRequestObject(request); + currResult.setStartDate(new Date()); if (opContext.getSendingRequestEventHandler().hasListeners()) { - opContext.getSendingRequestEventHandler().fireEvent(new SendingRequestEvent(opContext, request)); + opContext.getSendingRequestEventHandler() + .fireEvent(new SendingRequestEvent(opContext, request, currResult)); } // Send the request @@ -316,25 +320,9 @@ public static RequestResult processRequest(final HttpURLConnection request, fina currResult.setContentMD5(BaseResponse.getContentMD5(request)); if (opContext.getResponseReceivedEventHandler().hasListeners()) { - opContext.getResponseReceivedEventHandler().fireEvent(new ResponseReceivedEvent(opContext, request)); - } - - return currResult; - } - - /** - * Sets the exception on the last request result in a safe way, if there is no last result one is added. - * - * @param opContext - * an object used to track the execution of the operation - * @param exceptionToSet - * the exception to set on the result. - */ - private static void setLastException(final OperationContext opContext, final Exception exceptionToSet) { - if (opContext.getLastResult() == null) { - opContext.getRequestResults().add(new RequestResult()); + opContext.getResponseReceivedEventHandler().fireEvent( + new ResponseReceivedEvent(opContext, request, currResult)); } - opContext.getLastResult().setException(exceptionToSet); } /** diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java index 32ff5a00459a0..803bbdfa5481c 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/storage/utils/implementation/StorageOperation.java @@ -109,8 +109,11 @@ public final RequestResult getResult() { /** * Resets the operation status flags between operations. */ - protected final void initialize() { - this.setResult(new RequestResult()); + protected final void initialize(OperationContext opContext) { + RequestResult currResult = new RequestResult(); + this.setResult(currResult); + opContext.appendRequestResult(currResult); + this.setException(null); this.setNonExceptionedRetryableFailure(false); } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java new file mode 100644 index 0000000000000..973b9b53c3e2c --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java @@ -0,0 +1,107 @@ +/** + * 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.windowsazure.services.media.implementation.content; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +/** + * This type maps the XML returned in the odata ATOM serialization + * for ErrorDetail entities. + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +public class TaskHistoricalEventType implements MediaServiceDTO { + + /** The code. */ + @XmlElement(name = "Code", namespace = Constants.ODATA_DATA_NS) + protected String code; + + /** The message. */ + @XmlElement(name = "Message", namespace = Constants.ODATA_DATA_NS) + protected String message; + + /** The time stamp. */ + @XmlElement(name = "TimeStamp", namespace = Constants.ODATA_DATA_NS) + protected Date timeStamp; + + /** + * Gets the code. + * + * @return the code + */ + public String getCode() { + return code; + } + + /** + * Sets the code. + * + * @param code + * the id to set + * @return the error detail type + */ + public TaskHistoricalEventType setCode(String code) { + this.code = code; + return this; + } + + /** + * Gets the message. + * + * @return the message + */ + public String getMessage() { + return message; + } + + /** + * Sets the message. + * + * @param message + * the message to set + * @return the error detail type + */ + public TaskHistoricalEventType setMessage(String message) { + this.message = message; + return this; + } + + /** + * Gets the time stamp. + * + * @return the time stamp + */ + public Date getTimeStamp() { + return timeStamp; + } + + /** + * Sets the time stamp. + * + * @param timeStamp + * the time stamp + * @return the task historical event type + */ + public TaskHistoricalEventType setTimeStamp(Date timeStamp) { + this.timeStamp = timeStamp; + return this; + } + +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java index 9436ca9ab0255..e6486eb697d0b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java @@ -44,6 +44,10 @@ public class TaskType implements MediaServiceDTO { @XmlElement(name = "element", namespace = Constants.ODATA_DATA_NS) protected List errorDetails; + @XmlElementWrapper(name = "HistoricalEvents", namespace = Constants.ODATA_DATA_NS) + @XmlElement(name = "element", namespace = Constants.ODATA_DATA_NS) + protected List historicalEventTypes; + @XmlElement(name = "MediaProcessorId", namespace = Constants.ODATA_DATA_NS) protected String mediaProcessorId; @@ -269,4 +273,13 @@ public TaskType setInputMediaAssets(List inputMediaAssets) { this.inputMediaAssets = inputMediaAssets; return this; } + + public List getHistoricalEventTypes() { + return historicalEventTypes; + } + + public TaskType setHistoricalEventTypes(List historicalEventTypes) { + this.historicalEventTypes = historicalEventTypes; + return this; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java new file mode 100644 index 0000000000000..14d44fc85142e --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java @@ -0,0 +1,76 @@ +/* + * 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.windowsazure.services.media.models; + +import java.util.Date; + +/** + * The Class TaskHistoricalEvent. + */ +public class TaskHistoricalEvent { + + /** The code. */ + private final String code; + + /** The message. */ + private final String message; + + /** The time stamp. */ + private final Date timeStamp; + + /** + * Instantiates a new error detail. + * + * @param code + * the code + * @param message + * the message + * @param timeStamp + * the time stamp + */ + public TaskHistoricalEvent(String code, String message, Date timeStamp) { + this.code = code; + this.message = message; + this.timeStamp = timeStamp; + } + + /** + * Gets the code. + * + * @return the code + */ + public String getCode() { + return this.code; + } + + /** + * Gets the message. + * + * @return the message + */ + public String getMessage() { + return this.message; + } + + /** + * Gets the time stamp. + * + * @return the time stamp + */ + public Date getTimeStamp() { + return this.timeStamp; + } +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java index 8e8c3cd110877..6f22c00bb7697 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java @@ -22,6 +22,7 @@ import com.microsoft.windowsazure.services.media.implementation.ODataEntity; import com.microsoft.windowsazure.services.media.implementation.atom.EntryType; import com.microsoft.windowsazure.services.media.implementation.content.ErrorDetailType; +import com.microsoft.windowsazure.services.media.implementation.content.TaskHistoricalEventType; import com.microsoft.windowsazure.services.media.implementation.content.TaskType; /** @@ -86,6 +87,30 @@ public List getErrorDetails() { return null; } + /** + * Gets the task historical events. + * + * @return the task historical events + */ + public List getHistoricalEvents() { + List result = new ArrayList(); + List historicalEventTypes = getContent().getHistoricalEventTypes(); + + if (historicalEventTypes != null) { + for (TaskHistoricalEventType taskHistoricalEventType : historicalEventTypes) { + String message = taskHistoricalEventType.getMessage(); + if ((message != null) && (message.isEmpty())) { + message = null; + } + TaskHistoricalEvent taskHistoricalEvent = new TaskHistoricalEvent(taskHistoricalEventType.getCode(), + message, taskHistoricalEventType.getTimeStamp()); + result.add(taskHistoricalEvent); + } + } + + return result; + } + /** * Gets the media processor id. * @@ -213,7 +238,7 @@ public String getInitializationVector() { } /** - * Gets link to the task's input assets + * Gets link to the task's input assets. * * @return the link */ @@ -222,7 +247,7 @@ public LinkInfo getInputAssetsLink() { } /** - * Gets link to the task's output assets + * Gets link to the task's output assets. * * @return the link */ diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java index 93771ce03de9e..c29f1067844c6 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueue.java @@ -220,7 +220,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(messageBytes); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED) { this.setNonExceptionedRetryableFailure(true); @@ -286,7 +286,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -351,7 +351,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final QueueRequest.addMetadata(request, queue.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_CREATED && this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { @@ -424,7 +424,7 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, QueueRequest.addMetadata(request, queue.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_CREATED) { return true; @@ -509,7 +509,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -580,7 +580,7 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NO_CONTENT) { return true; @@ -667,7 +667,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -733,7 +733,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -806,7 +806,7 @@ public Boolean execute(final CloudQueueClient client, final CloudQueue queue, client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { return Boolean.valueOf(true); @@ -1021,7 +1021,7 @@ public ArrayList execute(final CloudQueueClient client, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1155,7 +1155,7 @@ public ArrayList execute(final CloudQueueClient client, final client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1293,7 +1293,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final client.getCredentials().signRequest(request, 0L); } - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -1366,7 +1366,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final QueueRequest.addMetadata(request, queue.metadata, opContext); client.getCredentials().signRequest(request, 0L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -1445,7 +1445,7 @@ public Void execute(final CloudQueueClient client, final CloudQueue queue, final final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -1515,7 +1515,7 @@ public QueuePermissions execute(final CloudQueueClient client, final CloudQueue client.getCredentials().signRequest(request, -1L); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); @@ -1545,11 +1545,11 @@ public QueuePermissions execute(final CloudQueueClient client, final CloudQueue * A queue-level access policy. * @return A shared access signature for the queue. * @throws InvalidKeyException - * If an invalid key was passed. + * If an invalid key was passed. * @throws StorageException - * If a storage service error occurred. + * If a storage service error occurred. * @throws IllegalArgumentException - * If an unexpected value is passed. + * If an unexpected value is passed. */ public String generateSharedAccessSignature(final SharedAccessQueuePolicy policy, final String groupPolicyIdentifier) throws InvalidKeyException, StorageException { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java index 0ca46aaf25bc3..addec40b3b9cd 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/client/CloudQueueClient.java @@ -227,7 +227,7 @@ ResultSegment listQueuesCore(final String prefix, final QueueListing this.getCredentials().signRequest(listQueueRequest, -1L); - taskReference.setResult(ExecutionEngine.processRequest(listQueueRequest, opContext)); + ExecutionEngine.processRequest(listQueueRequest, opContext, taskReference.getResult()); if (taskReference.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { taskReference.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java index 536b3adfb5821..f13eac657acfc 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTable.java @@ -493,7 +493,7 @@ public Void execute(final CloudTableClient client, final CloudTable table, final final OutputStream outStreamRef = request.getOutputStream(); outStreamRef.write(aclBytes); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) { this.setNonExceptionedRetryableFailure(true); @@ -564,7 +564,7 @@ public TablePermissions execute(final CloudTableClient client, final CloudTable client.getCredentials().signRequestLite(request, -1L, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { this.setNonExceptionedRetryableFailure(true); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java index e49f6e3fdfca6..26a506cc39a65 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/CloudTableClient.java @@ -800,7 +800,7 @@ protected ResultSegment executeQuerySegmentedCore( this.getCredentials().signRequestLite(queryRequest, -1L, opContext); - taskReference.setResult(ExecutionEngine.processRequest(queryRequest, opContext)); + ExecutionEngine.processRequest(queryRequest, opContext, taskReference.getResult()); if (taskReference.getResult().getStatusCode() != HttpURLConnection.HTTP_OK) { throw TableServiceException.generateTableServiceException(true, taskReference.getResult(), null, diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java index bc5c112c31876..14c130540b18c 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/QueryTableOperation.java @@ -189,7 +189,7 @@ tableName, generateRequestIdentity(isTableEntry, operation.getPartitionKey(), fa client.getCredentials().signRequestLite(request, -1L, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_OK) { // Parse response for updates diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java index 4f81296856b6f..a2e814a92e00a 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableBatchOperation.java @@ -399,10 +399,9 @@ public ArrayList execute(final CloudTableClient client, final Table MimeHelper.writeBatchToStream(request.getOutputStream(), tableName, batch, batchID, changeSet, opContext); - final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext); + final InputStream streamRef = ExecutionEngine.getInputStream(request, opContext, this.getResult()); ArrayList responseParts = null; try { - this.setResult(opContext.getLastResult()); final String contentType = request.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE); final String[] headerVals = contentType.split("multipart/mixed; boundary="); diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java index 130d59fe9914d..65987567691ce 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/client/TableOperation.java @@ -256,13 +256,13 @@ private TableResult performDelete(final CloudTableClient client, final String ta public TableResult execute(final CloudTableClient client, final TableOperation operation, final OperationContext opContext) throws Exception { - final HttpURLConnection request = TableRequest.delete(client.getTransformedEndPoint(opContext), tableName, - generateRequestIdentity(isTableEntry, tableIdentity, false), operation.getEntity().getEtag(), - options.getTimeoutIntervalInMs(), null, options, opContext); + final HttpURLConnection request = TableRequest.delete(client.getTransformedEndPoint(opContext), + tableName, generateRequestIdentity(isTableEntry, tableIdentity, false), operation.getEntity() + .getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); client.getCredentials().signRequestLite(request, -1L, opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND || this.getResult().getStatusCode() == HttpURLConnection.HTTP_CONFLICT) { @@ -323,8 +323,8 @@ private TableResult performInsert(final CloudTableClient client, final String ta @Override public TableResult execute(final CloudTableClient client, final TableOperation operation, final OperationContext opContext) throws Exception { - final HttpURLConnection request = TableRequest.insert(client.getTransformedEndPoint(opContext), tableName, - generateRequestIdentity(isTableEntry, tableIdentity, false), + final HttpURLConnection request = TableRequest.insert(client.getTransformedEndPoint(opContext), + tableName, generateRequestIdentity(isTableEntry, tableIdentity, false), operation.opType != TableOperationType.INSERT ? operation.getEntity().getEtag() : null, operation.opType.getUpdateType(), options.getTimeoutIntervalInMs(), null, options, opContext); @@ -333,7 +333,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o AtomPubParser.writeSingleEntityToStream(operation.getEntity(), isTableEntry, request.getOutputStream(), opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (operation.opType == TableOperationType.INSERT) { if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_CONFLICT) { throw TableServiceException.generateTableServiceException(false, this.getResult(), operation, @@ -410,8 +410,8 @@ private TableResult performMerge(final CloudTableClient client, final String tab public TableResult execute(final CloudTableClient client, final TableOperation operation, final OperationContext opContext) throws Exception { - final HttpURLConnection request = TableRequest.merge(client.getTransformedEndPoint(opContext), tableName, - generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), + final HttpURLConnection request = TableRequest.merge(client.getTransformedEndPoint(opContext), + tableName, generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); client.getCredentials().signRequestLite(request, -1L, opContext); @@ -419,7 +419,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o AtomPubParser.writeSingleEntityToStream(operation.getEntity(), false, request.getOutputStream(), opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND || this.getResult().getStatusCode() == HttpURLConnection.HTTP_CONFLICT) { @@ -476,8 +476,8 @@ private TableResult performUpdate(final CloudTableClient client, final String ta public TableResult execute(final CloudTableClient client, final TableOperation operation, final OperationContext opContext) throws Exception { - final HttpURLConnection request = TableRequest.update(client.getTransformedEndPoint(opContext), tableName, - generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), + final HttpURLConnection request = TableRequest.update(client.getTransformedEndPoint(opContext), + tableName, generateRequestIdentity(false, null, false), operation.getEntity().getEtag(), options.getTimeoutIntervalInMs(), null, options, opContext); client.getCredentials().signRequestLite(request, -1L, opContext); @@ -485,7 +485,7 @@ public TableResult execute(final CloudTableClient client, final TableOperation o AtomPubParser.writeSingleEntityToStream(operation.getEntity(), false, request.getOutputStream(), opContext); - this.setResult(ExecutionEngine.processRequest(request, opContext)); + ExecutionEngine.processRequest(request, opContext, this.getResult()); if (this.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_FOUND || this.getResult().getStatusCode() == HttpURLConnection.HTTP_CONFLICT) { @@ -686,7 +686,8 @@ protected TableResult parseResponse(final XMLStreamReader xmlr, final int httpSt resObj = new TableResult(httpStatusCode); resObj.setResult(this.getEntity()); - if (this.opType != TableOperationType.DELETE) { + if (this.opType != TableOperationType.DELETE && etagFromHeader != null) { + resObj.setEtag(etagFromHeader); this.getEntity().setEtag(etagFromHeader); } } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java index f16cfe5a2db6d..e007c41511408 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/CloudBlobContainerTests.java @@ -688,6 +688,7 @@ public void testSendingRequestEventBlob() throws StorageException, URISyntaxExce @Override public void eventOccurred(SendingRequestEvent eventArg) { + Assert.assertEquals(eventArg.getRequestResult(), eventArg.getOpContext().getLastResult()); callList.add(true); } }); @@ -719,6 +720,43 @@ public void eventOccurred(SendingRequestEvent eventArg) { } } + @Test + public void testBlobInputStream() throws URISyntaxException, StorageException, IOException { + final int blobLength = 16 * 1024; + final Random randGenerator = new Random(); + String blobName = "testblob" + Integer.toString(randGenerator.nextInt(50000)); + blobName = blobName.replace('-', '_'); + + final CloudBlobContainer containerRef = bClient.getContainerReference(BlobTestBase.testSuiteContainerName); + + final CloudBlockBlob blobRef = containerRef.getBlockBlobReference(blobName); + + final byte[] buff = new byte[blobLength]; + randGenerator.nextBytes(buff); + buff[0] = -1; + buff[1] = -128; + final ByteArrayInputStream sourceStream = new ByteArrayInputStream(buff); + + final BlobRequestOptions options = new BlobRequestOptions(); + final OperationContext operationContext = new OperationContext(); + options.setStoreBlobContentMD5(true); + options.setTimeoutIntervalInMs(90000); + options.setRetryPolicyFactory(new RetryNoRetry()); + blobRef.uploadFullBlob(sourceStream, blobLength, null, options, operationContext); + + BlobInputStream blobStream = blobRef.openInputStream(); + + for (int i = 0; i < blobLength; i++) { + int data = blobStream.read(); + Assert.assertTrue(data >= 0); + Assert.assertEquals(buff[i], (byte) data); + } + + Assert.assertEquals(-1, blobStream.read()); + + blobRef.delete(); + } + @Test public void testCurrentOperationByteCount() throws URISyntaxException, StorageException, IOException { final int blockLength = 4 * 1024 * 1024; @@ -750,6 +788,7 @@ public void testCurrentOperationByteCount() throws URISyntaxException, StorageEx BlobRequestOptions options = new BlobRequestOptions(); options.setTimeoutIntervalInMs(2000); options.setRetryPolicyFactory(new RetryNoRetry()); + ByteArrayOutputStream downloadedDataStream = new ByteArrayOutputStream(); try { blobRef.download(downloadedDataStream, null, options, operationContext); @@ -769,5 +808,4 @@ public void testCurrentOperationByteCount() throws URISyntaxException, StorageEx blobRef.delete(); } - } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java index 964bafa5072ea..2b2e78d125e86 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java @@ -98,7 +98,7 @@ public void uploadAesProtectedAssetAndDownloadSuccess() throws Exception { uploadEncryptedAssetFile(assetInfo, blobWriter, "MPEG4-H264.mp4", encryptedContent, contentKeyId, iv); // submit and execute the decoding job. - JobInfo jobInfo = decodeAsset("uploadAesProtectedAssetSuccess", assetInfo.getId()); + JobInfo jobInfo = decodeAsset(testJobPrefix + "uploadAesProtectedAssetSuccess", assetInfo.getId()); // assert LinkInfo taskLinkInfo = jobInfo.getTasksLink(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java index ffa12bb064fa4..6e125ca859b16 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java @@ -101,8 +101,8 @@ protected static void cleanupEnvironment() { removeAllTestLocators(); removeAllTestAssets(); removeAllTestAccessPolicies(); - removeAllTestContentKeys(); removeAllTestJobs(); + removeAllTestContentKeys(); } private static void removeAllTestContentKeys() { diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java index 608aba0901e06..a8032b0bdd3df 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java @@ -35,6 +35,7 @@ import com.microsoft.windowsazure.services.media.models.ListResult; import com.microsoft.windowsazure.services.media.models.Task; import com.microsoft.windowsazure.services.media.models.Task.CreateBatchOperation; +import com.microsoft.windowsazure.services.media.models.TaskHistoricalEvent; import com.microsoft.windowsazure.services.media.models.TaskInfo; public class JobIntegrationTest extends IntegrationTestBase { @@ -343,4 +344,32 @@ public void canGetInputOutputAssetsFromTask() throws Exception { assertTrue(outputs.get(0).getName().contains(name)); } + @Test + public void canGetTaskHistoricalEventsFromTask() throws Exception { + // Arrange + String jobName = testJobPrefix + "canGetTaskHistoricalEventsFromTask"; + int priority = 3; + int retryCounter = 0; + + // Act + JobInfo actualJobInfo = service.create(Job.create().setName(jobName).setPriority(priority) + .addInputMediaAsset(assetInfo.getId()).addTaskCreator(getTaskCreator(0))); + + while (actualJobInfo.getState().getCode() < 3 && retryCounter < 30) { + Thread.sleep(10000); + actualJobInfo = service.get(Job.get(actualJobInfo.getId())); + retryCounter++; + } + ListResult tasks = service.list(Task.list(actualJobInfo.getTasksLink())); + TaskInfo taskInfo = tasks.get(0); + List historicalEvents = taskInfo.getHistoricalEvents(); + TaskHistoricalEvent historicalEvent = historicalEvents.get(0); + + // Assert + assertTrue(historicalEvents.size() >= 5); + assertNotNull(historicalEvent.getCode()); + assertNotNull(historicalEvent.getTimeStamp()); + assertNull(historicalEvent.getMessage()); + } + } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java index 9258e5931787f..53c95807d4650 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/CloudQueueTests.java @@ -1112,6 +1112,8 @@ public void testPeekMessagesFromEmptyQueue() throws URISyntaxException, StorageE @Test public void testUpdateMessage() throws URISyntaxException, StorageException, UnsupportedEncodingException { + queue.clear(); + String messageContent = "messagetest"; CloudQueueMessage message1 = new CloudQueueMessage(messageContent); queue.addMessage(message1); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/IntegrationTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/IntegrationTestBase.java index ddff90ded3445..aa8c21ec5cbbc 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/IntegrationTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/serviceBus/IntegrationTestBase.java @@ -16,6 +16,7 @@ import static com.microsoft.windowsazure.services.serviceBus.Util.*; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -54,7 +55,7 @@ public void initialize() throws Exception { for (TopicInfo topic : iterateTopics(service)) { String topicName = topic.getPath(); if (topicName.startsWith("Test") || topicName.startsWith("test")) { - service.deleteQueue(topicName); + service.deleteTopic(topicName); } } if (!testAlphaExists) { @@ -62,6 +63,24 @@ public void initialize() throws Exception { } } + @AfterClass + public static void cleanUpTestArtifacts() throws Exception { + Configuration config = createConfiguration(); + ServiceBusContract service = ServiceBusService.create(config); + for (QueueInfo queue : iterateQueues(service)) { + String queueName = queue.getPath(); + if (queueName.startsWith("Test") || queueName.startsWith("test")) { + service.deleteQueue(queueName); + } + } + for (TopicInfo topic : iterateTopics(service)) { + String topicName = topic.getPath(); + if (topicName.startsWith("Test") || topicName.startsWith("test")) { + service.deleteTopic(topicName); + } + } + } + protected static Configuration createConfiguration() throws Exception { Configuration config = Configuration.load(); overrideWithEnv(config, ServiceBusConfiguration.CONNECTION_STRING); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableOperationTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableOperationTests.java index 3421fcbe2b6f2..cb11cfbfe12df 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableOperationTests.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableOperationTests.java @@ -145,6 +145,7 @@ public void insertOrMerge() throws StorageException { TableResult insertResult = tClient.execute(testSuiteTableName, TableOperation.insertOrMerge(baseEntity)); Assert.assertEquals(insertResult.getHttpStatusCode(), HttpURLConnection.HTTP_NO_CONTENT); + Assert.assertNotNull(insertResult.getEtag()); // Insert or replace Entity - ENTITY EXISTS -> WILL REPLACE tClient.execute(testSuiteTableName, TableOperation.insertOrMerge(secondEntity)); @@ -206,6 +207,7 @@ public void insertOrReplace() throws StorageException { TableResult insertResult = tClient.execute(testSuiteTableName, TableOperation.insertOrReplace(baseEntity)); Assert.assertEquals(insertResult.getHttpStatusCode(), HttpURLConnection.HTTP_NO_CONTENT); + Assert.assertNotNull(insertResult.getEtag()); // Insert or replace Entity - ENTITY EXISTS -> WILL REPLACE tClient.execute(testSuiteTableName, TableOperation.insertOrReplace(secondEntity)); @@ -259,7 +261,10 @@ public void merge() throws StorageException { secondEntity.setRowKey(baseEntity.getRowKey()); secondEntity.setEtag(baseEntity.getEtag()); - tClient.execute(testSuiteTableName, TableOperation.merge(secondEntity)); + TableResult mergeResult = tClient.execute(testSuiteTableName, TableOperation.merge(secondEntity)); + + Assert.assertEquals(mergeResult.getHttpStatusCode(), HttpURLConnection.HTTP_NO_CONTENT); + Assert.assertNotNull(mergeResult.getEtag()); TableResult res2 = tClient.execute(testSuiteTableName, TableOperation.retrieve(secondEntity.getPartitionKey(), secondEntity.getRowKey(), DynamicTableEntity.class)); @@ -456,7 +461,10 @@ public void replace() throws StorageException { // Remove property and update retrievedEntity.getProperties().remove("D"); - tClient.execute(testSuiteTableName, TableOperation.replace(retrievedEntity)); + TableResult replaceResult = tClient.execute(testSuiteTableName, TableOperation.replace(retrievedEntity)); + + Assert.assertEquals(replaceResult.getHttpStatusCode(), HttpURLConnection.HTTP_NO_CONTENT); + Assert.assertNotNull(replaceResult.getEtag()); // Retrieve Entity queryResult = tClient