@Test public void testOpenOutputStreamNoArgs() throws URISyntaxException, StorageException { String blobName = BlobTestHelper.generateRandomBlobNameWithPrefix("testblob"); CloudPageBlob pageBlob = this.container.getPageBlobReference(blobName); try { pageBlob.openWriteExisting(); } catch (StorageException ex) { assertEquals("The specified blob does not exist.", ex.getMessage()); assertEquals(HttpURLConnection.HTTP_NOT_FOUND, ex.getHttpStatusCode()); } pageBlob.openWriteNew(1024); pageBlob.openWriteExisting(); CloudPageBlob pageBlob2 = this.container.getPageBlobReference(blobName); pageBlob2.downloadAttributes(); assertEquals(1024, pageBlob2.getProperties().getLength()); assertEquals(BlobType.PAGE_BLOB, pageBlob2.getProperties().getBlobType()); }
/** * 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(); } } } }