private static void safeOverwrite ( Blob origBlob , InputStream content ) { BlobStoreConnection connection = origBlob . getConnection ( ) ; String origId = origBlob . getId ( ) . toString ( ) ; // write new content to origId/new Blob newBlob = null ; try { newBlob = connection . getBlob ( new URI ( origId + "/new" ) , null ) ; copy ( content , newBlob . openOutputStream ( - 1 , false ) ) ; } catch ( Throwable th ) { // any error or exception here is an unrecoverable fault throw new FaultException ( th ) ; } // At this point, we have origId (with old content) and origId/new // rename origId to origId/old Blob oldBlob = null ; try { oldBlob = rename ( origBlob , origId + "/old" ) ; } finally { if ( oldBlob == null ) { // rename failed; attempt recovery before throwing the fault try { delete ( newBlob ) ; } catch ( Throwable th ) { logger . error ( "Failed to delete " + newBlob . getId ( ) + " while" + " recovering from rename failure during safe" + " overwrite" , th ) ; } } } // At this point, we have origId/old and origId/new // rename origId/new to origId boolean successful = false ; try { rename ( newBlob , origId ) ; successful = true ; } finally { if ( ! successful ) { // rename failed; attempt recovery before throwing the fault try { rename ( oldBlob , origId ) ; } catch ( Throwable th ) { logger . error ( "Failed to rename " + oldBlob . getId ( ) + " to " + origId + " while recovering from rename" + " failure during safe overwrite" , th ) ; } try { newBlob . delete ( ) ; } catch ( Throwable th ) { logger . error ( "Failed to delete " + newBlob . getId ( ) + " while recovering from rename" + " failure during safe overwrite" , th ) ; } } } // At this point, we have origId (with new content) and origId/old // remove origId/old; we don't need it anymore try { delete ( oldBlob ) ; } catch ( Throwable th ) { logger . error ( "Failed to delete " + oldBlob . getId ( ) + " while cleaning up after committed" + " safe overwrite" , th ) ; } }
Overwrites the content of the given blob in a way that guarantees the original content is not destroyed until the replacement is successfully put in its place .