@@ -1272,7 +1272,45 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr
12721272 long writeLength , final boolean rewindSourceStream , final boolean calculateMD5 , OperationContext opContext ,
12731273 final RequestOptions options , final Boolean shouldFlush ) throws IOException , StorageException {
12741274 return writeToOutputStream (sourceStream , outStream , writeLength , rewindSourceStream , calculateMD5 , opContext ,
1275- options , shouldFlush , null /*StorageRequest*/ );
1275+ options , shouldFlush , null /*StorageRequest*/ , null /* descriptor */ );
1276+ }
1277+
1278+ /**
1279+ * Reads data from an input stream and writes it to an output stream, calculates the length of the data written, and
1280+ * optionally calculates the MD5 hash for the data.
1281+ *
1282+ * @param sourceStream
1283+ * An <code>InputStream</code> object that represents the input stream to use as the source.
1284+ * @param outStream
1285+ * An <code>OutputStream</code> object that represents the output stream to use as the destination.
1286+ * @param writeLength
1287+ * The number of bytes to read from the stream.
1288+ * @param rewindSourceStream
1289+ * <code>true</code> if the input stream should be rewound <strong>before</strong> it is read; otherwise,
1290+ * <code>false</code>
1291+ * @param calculateMD5
1292+ * <code>true</code> if an MD5 hash will be calculated; otherwise, <code>false</code>.
1293+ * @param opContext
1294+ * An {@link OperationContext} object that represents the context for the current operation. This object
1295+ * is used to track requests to the storage service, and to provide additional runtime information about
1296+ * the operation.
1297+ * @param options
1298+ * A {@link RequestOptions} object that specifies any additional options for the request. Namely, the
1299+ * maximum execution time.
1300+ * @param request
1301+ * Used by download resume to set currentRequestByteCount on the request. Otherwise, null is always used.
1302+ * @return A {@link StreamMd5AndLength} object that contains the output stream length, and optionally the MD5 hash.
1303+ *
1304+ * @throws IOException
1305+ * If an I/O error occurs.
1306+ * @throws StorageException
1307+ * If a storage service error occurred.
1308+ */
1309+ public static StreamMd5AndLength writeToOutputStream (final InputStream sourceStream , final OutputStream outStream ,
1310+ long writeLength , final boolean rewindSourceStream , final boolean calculateMD5 , OperationContext opContext ,
1311+ final RequestOptions options , final Boolean shouldFlush , StorageRequest <?, ?, Integer > request )
1312+ throws IOException , StorageException {
1313+ return writeToOutputStream (sourceStream , outStream , writeLength , rewindSourceStream , calculateMD5 , opContext , options , shouldFlush , request , null /* descriptor */ );
12761314 }
12771315
12781316 /**
@@ -1299,6 +1337,11 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr
12991337 * maximum execution time.
13001338 * @param request
13011339 * Used by download resume to set currentRequestByteCount on the request. Otherwise, null is always used.
1340+ * @param descriptor
1341+ * A {@Link StreamMd5AndLength} object to append to in the case of recovery action or null if this is not called
1342+ * from a recovery. This value needs to be passed for recovery in case part of the body has already been read,
1343+ * the recovery will attempt to download the remaining bytes but will do MD5 validation on the originally
1344+ * requested range size.
13021345 * @return A {@link StreamMd5AndLength} object that contains the output stream length, and optionally the MD5 hash.
13031346 *
13041347 * @throws IOException
@@ -1308,24 +1351,28 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr
13081351 */
13091352 public static StreamMd5AndLength writeToOutputStream (final InputStream sourceStream , final OutputStream outStream ,
13101353 long writeLength , final boolean rewindSourceStream , final boolean calculateMD5 , OperationContext opContext ,
1311- final RequestOptions options , final Boolean shouldFlush , StorageRequest <?, ?, Integer > request )
1354+ final RequestOptions options , final Boolean shouldFlush , StorageRequest <?, ?, Integer > request , StreamMd5AndLength descriptor )
13121355 throws IOException , StorageException {
13131356 if (rewindSourceStream && sourceStream .markSupported ()) {
13141357 sourceStream .reset ();
13151358 sourceStream .mark (Constants .MAX_MARK_LENGTH );
13161359 }
13171360
1318- final StreamMd5AndLength retVal = new StreamMd5AndLength ();
1319-
1320- if (calculateMD5 ) {
1321- try {
1322- retVal .setDigest (MessageDigest .getInstance ("MD5" ));
1323- }
1324- catch (final NoSuchAlgorithmException e ) {
1325- // This wont happen, throw fatal.
1326- throw Utility .generateNewUnexpectedStorageException (e );
1361+ if (descriptor == null ) {
1362+ descriptor = new StreamMd5AndLength ();
1363+ if (calculateMD5 ) {
1364+ try {
1365+ descriptor .setDigest (MessageDigest .getInstance ("MD5" ));
1366+ }
1367+ catch (final NoSuchAlgorithmException e ) {
1368+ // This wont happen, throw fatal.
1369+ throw Utility .generateNewUnexpectedStorageException (e );
1370+ }
13271371 }
13281372 }
1373+ else {
1374+ descriptor .setMd5 (null );
1375+ }
13291376
13301377 if (writeLength < 0 ) {
13311378 writeLength = Long .MAX_VALUE ;
@@ -1349,25 +1396,26 @@ public static StreamMd5AndLength writeToOutputStream(final InputStream sourceStr
13491396 }
13501397
13511398 if (calculateMD5 ) {
1352- retVal .getDigest ().update (retrievedBuff , 0 , count );
1399+ descriptor .getDigest ().update (retrievedBuff , 0 , count );
13531400 }
13541401
1355- retVal .setLength (retVal .getLength () + count );
1356- retVal .setCurrentOperationByteCount (retVal .getCurrentOperationByteCount () + count );
1402+ descriptor .setLength (descriptor .getLength () + count );
1403+ descriptor .setCurrentOperationByteCount (descriptor .getCurrentOperationByteCount () + count );
13571404
13581405 if (request != null ) {
13591406 request .setCurrentRequestByteCount (request .getCurrentRequestByteCount () + count );
1407+ request .setCurrentDescriptor (descriptor );
13601408 }
13611409
1362- nextCopy = (int ) Math .min (retrievedBuff .length , writeLength - retVal .getLength ());
1410+ nextCopy = (int ) Math .min (retrievedBuff .length , writeLength - descriptor .getLength ());
13631411 count = sourceStream .read (retrievedBuff , 0 , nextCopy );
13641412 }
13651413
13661414 if (outStream != null && shouldFlush ) {
13671415 outStream .flush ();
13681416 }
13691417
1370- return retVal ;
1418+ return descriptor ;
13711419 }
13721420
13731421 /**
0 commit comments