@Test public void testBlobUploadWithoutMD5Validation() throws URISyntaxException, StorageException, IOException { final String pageBlobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testPageBlob"); final CloudPageBlob pageBlobRef = this.container.getPageBlobReference(pageBlobName); final int length = 2 * 1024; ByteArrayInputStream srcStream = BlobTestHelper.getRandomDataStream(length); BlobRequestOptions options = new BlobRequestOptions(); options.setDisableContentMD5Validation(false); options.setStoreBlobContentMD5(false); pageBlobRef.upload(srcStream, length, null, options, null); pageBlobRef.downloadAttributes(); pageBlobRef.getProperties().setContentMD5("MDAwMDAwMDA="); pageBlobRef.uploadProperties(null, options, null); try { pageBlobRef.download(new ByteArrayOutputStream(), null, options, null); fail(); } catch (StorageException ex) { assertEquals(306, ex.getHttpStatusCode()); assertEquals("InvalidMd5", ex.getErrorCode()); } options.setDisableContentMD5Validation(true); pageBlobRef.download(new ByteArrayOutputStream(), null, options, null); }
/** * Start copying a blob and then abort * * @throws StorageException * @throws URISyntaxException * @throws IOException * @throws InterruptedException */ @Test public void testCopyFromPageBlobAbortTest() throws StorageException, URISyntaxException, IOException { final int length = 512; CloudPageBlob originalBlob = (CloudPageBlob) BlobTestHelper.uploadNewBlob( this.container, BlobType.PAGE_BLOB, "originalBlob", length, null); CloudPageBlob copyBlob = this.container.getPageBlobReference(originalBlob.getName() + "copyed"); copyBlob.startCopy(originalBlob); try { copyBlob.abortCopy(copyBlob.getProperties().getCopyState().getCopyId()); } catch (StorageException e) { if (!e.getErrorCode().contains("NoPendingCopyOperation")) { throw e; } } }
/** * Deletes the directory if it exists using the specified request options and operation context. * * @param accessCondition An {@link AccessCondition} object that represents the access conditions * for the directory. * @param options A {@link FileRequestOptions} object that specifies any additional options for * the request. Specifying <code>null</code> will use the default request options from the * associated service client ( {@link CloudFileClient}). * @param opContext An {@link OperationContext} object that represents the context for the current * operation. This object is used to track requests to the storage service, and to provide * additional runtime information about the operation. * @return <code>true</code> if the directory existed and was deleted; otherwise, <code>false * </code>. * @throws StorageException If a storage service error occurred. */ @DoesServiceRequest public boolean deleteIfExists( AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); boolean exists = this.exists(true /* primaryOnly */, accessCondition, options, opContext); if (exists) { try { this.delete(accessCondition, options, opContext); return true; } catch (StorageException e) { if (e.getHttpStatusCode() == HttpURLConnection.HTTP_NOT_FOUND && StorageErrorCodeStrings.RESOURCE_NOT_FOUND.equals(e.getErrorCode())) { return false; } else { throw e; } } } else { return false; } }
/** * Creates the directory if it does not exist, using the specified request options and operation * context. * * @param options A {@link FileRequestOptions} object that specifies any additional options for * the request. Specifying <code>null</code> will use the default request options from the * associated service client ({@link CloudFileClient}). * @param opContext An {@link OperationContext} object that represents the context for the current * operation. This object is used to track requests to the storage service, and to provide * additional runtime information about the operation. * @return <code>true</code> if the directory did not already exist and was created; otherwise, * <code>false</code>. * @throws StorageException If a storage service error occurred. */ @DoesServiceRequest public boolean createIfNotExists(FileRequestOptions options, OperationContext opContext) throws StorageException { options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); boolean exists = this.exists(true /* primaryOnly */, null /* accessCondition */, options, opContext); if (exists) { return false; } else { try { this.create(options, opContext); return true; } catch (StorageException e) { if (e.getHttpStatusCode() == HttpURLConnection.HTTP_CONFLICT && StorageErrorCodeStrings.RESOURCE_ALREADY_EXISTS.equals(e.getErrorCode())) { return false; } else { throw e; } } } }
/** * Executes an operation and enforces a retrypolicy to handle any potential errors * * @param <CLIENT_TYPE> The type of the service client * @param <PARENT_TYPE> The type of the parent object, i.e. CloudBlobContainer for * downloadAttributes etc. * @param <RESULT_TYPE> The type of the expected result * @param client the service client associated with the request * @param parentObject the parent object * @param task the StorageRequest to execute * @param policyFactory the factory used to generate a new retry policy instance * @param opContext an object used to track the execution of the operation * @return the result of the operation * @throws StorageException an exception representing any error which occurred during the * operation. */ public static <CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> RESULT_TYPE executeWithRetry( final CLIENT_TYPE client, final PARENT_TYPE parentObject, final StorageRequest<CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> task, final RetryPolicyFactory policyFactory, final OperationContext opContext) throws StorageException { RetryPolicy policy = null; if (policyFactory == null) { policy = new RetryNoRetry(); } else { policy = policyFactory.createInstance(opContext); // if the returned policy is null, set to not retry if (policy == null) { policy = new RetryNoRetry(); } } int currentRetryCount = 0; StorageException translatedException = null; HttpURLConnection request = null; final long startTime = new Date().getTime(); while (true) { try { // 1-4: setup the request request = setupStorageRequest(client, parentObject, task, currentRetryCount, opContext); Logger.info( opContext, LogConstants.START_REQUEST, request.getURL(), request.getRequestProperty(Constants.HeaderConstants.DATE)); // 5. Potentially upload data if (task.getSendStream() != null) { Logger.info(opContext, LogConstants.UPLOAD); final StreamMd5AndLength descriptor = Utility.writeToOutputStream( task.getSendStream(), request.getOutputStream(), task.getLength(), false /* rewindStream */, false /* calculate MD5 */, opContext, task.getRequestOptions()); task.validateStreamWrite(descriptor); Logger.info(opContext, LogConstants.UPLOADDONE); } // 6. Process the request - Get response RequestResult currResult = task.getResult(); currResult.setStartDate(new Date()); Logger.info(opContext, LogConstants.GET_RESPONSE); currResult.setStatusCode(request.getResponseCode()); currResult.setStatusMessage(request.getResponseMessage()); currResult.setStopDate(new Date()); currResult.setServiceRequestID(BaseResponse.getRequestId(request)); currResult.setEtag(BaseResponse.getEtag(request)); currResult.setRequestDate(BaseResponse.getDate(request)); currResult.setContentMD5(BaseResponse.getContentMD5(request)); // 7. Fire ResponseReceived Event ExecutionEngine.fireResponseReceivedEvent(opContext, request, task.getResult()); Logger.info( opContext, LogConstants.RESPONSE_RECEIVED, currResult.getStatusCode(), currResult.getServiceRequestID(), currResult.getContentMD5(), currResult.getEtag()); // 8. Pre-process response to check if there was an exception. Do Response parsing (headers // etc). Logger.info(opContext, LogConstants.PRE_PROCESS); RESULT_TYPE result = task.preProcessResponse(parentObject, client, opContext); Logger.info(opContext, LogConstants.PRE_PROCESS_DONE); if (!task.isNonExceptionedRetryableFailure()) { // 9. Post-process response. Read stream from server. Logger.info(opContext, LogConstants.POST_PROCESS); result = task.postProcessResponse(request, parentObject, client, opContext, result); Logger.info(opContext, LogConstants.POST_PROCESS_DONE); // Success return result and drain the input stream. if ((task.getResult().getStatusCode() >= 200) && (task.getResult().getStatusCode() < 300)) { if (request != null) { InputStream inStream = request.getInputStream(); // At this point, we already have a result / exception to return to the user. // This is just an optimization to improve socket reuse. try { Utility.writeToOutputStream( inStream, null, -1, false, false, null, task.getRequestOptions()); } catch (final IOException ex) { } catch (StorageException e) { } finally { inStream.close(); } } } Logger.info(opContext, LogConstants.COMPLETE); return result; } else { Logger.warn(opContext, LogConstants.UNEXPECTED_RESULT_OR_EXCEPTION); // The task may have already parsed an exception. translatedException = task.materializeException(task.getConnection(), opContext); task.getResult().setException(translatedException); // throw on non retryable status codes: 501, 505, blob type mismatch if (task.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_IMPLEMENTED || task.getResult().getStatusCode() == HttpURLConnection.HTTP_VERSION || translatedException .getErrorCode() .equals(StorageErrorCodeStrings.INVALID_BLOB_TYPE)) { throw translatedException; } } } catch (final TimeoutException e) { // Retryable Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); } catch (final SocketTimeoutException e) { // Retryable Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, "The operation did not complete in the specified time.", -1, null, e); task.getResult().setException(translatedException); } catch (final IOException e) { // Non Retryable if the inner exception is actually an TimeoutException, otherwise Retryable if (e.getCause() instanceof TimeoutException) { translatedException = new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null, (Exception) e.getCause()); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getCause().getClass().getName(), e.getCause().getMessage()); throw translatedException; } else { Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); } } catch (final InvalidKeyException e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw translatedException; } catch (final URISyntaxException e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw translatedException; } catch (final TableServiceException e) { task.getResult().setStatusCode(e.getHttpStatusCode()); task.getResult().setStatusMessage(e.getMessage()); task.getResult().setException(e); if (!e.isRetryable()) { Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw e; } else { Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = e; } } catch (final StorageException e) { // Non Retryable, just throw // do not translate StorageException task.getResult().setException(e); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw e; } catch (final Exception e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw translatedException; } finally { opContext.setClientTimeInMs(new Date().getTime() - startTime); // 10. Fire RequestCompleted Event if (task.isSent()) { ExecutionEngine.fireRequestCompletedEvent(opContext, request, task.getResult()); } } // Evaluate Retry Policy Logger.info( opContext, LogConstants.RETRY_CHECK, currentRetryCount, task.getResult().getStatusCode(), translatedException == null ? null : translatedException.getMessage()); task.setCurrentLocation(getNextLocation(task.getCurrentLocation(), task.getLocationMode())); Logger.info( opContext, LogConstants.NEXT_LOCATION, task.getCurrentLocation(), task.getLocationMode()); RetryContext retryContext = new RetryContext( currentRetryCount++, task.getResult(), task.getCurrentLocation(), task.getLocationMode()); RetryInfo retryInfo = policy.evaluate(retryContext, opContext); if (retryInfo == null) { // policy does not allow for retry Logger.error( opContext, LogConstants.DO_NOT_RETRY_POLICY, translatedException == null ? null : translatedException.getMessage()); throw translatedException; } else if (Utility.validateMaxExecutionTimeout( task.getRequestOptions().getOperationExpiryTimeInMs(), retryInfo.getRetryInterval())) { // maximum execution time would be exceeded by current time plus retry interval delay TimeoutException timeoutException = new TimeoutException(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION); translatedException = new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null, timeoutException); task.initialize(opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.DO_NOT_RETRY_TIMEOUT, translatedException == null ? null : translatedException.getMessage()); throw translatedException; } else { // attempt to retry task.setCurrentLocation(retryInfo.getTargetLocation()); task.setLocationMode(retryInfo.getUpdatedLocationMode()); Logger.info( opContext, LogConstants.RETRY_INFO, task.getCurrentLocation(), task.getLocationMode()); try { ExecutionEngine.fireRetryingEvent( opContext, task.getConnection(), task.getResult(), retryContext); Logger.info(opContext, LogConstants.RETRY_DELAY, retryInfo.getRetryInterval()); Thread.sleep(retryInfo.getRetryInterval()); } catch (final InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); } } } }