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);
}
}