1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.core.io; 17 18 import java.io.FileInputStream; 19 import java.io.InputStream; 20 import software.amazon.awssdk.annotations.NotThreadSafe; 21 import software.amazon.awssdk.annotations.SdkProtectedApi; 22 import software.amazon.awssdk.core.internal.io.Releasable; 23 import software.amazon.awssdk.utils.Logger; 24 25 /** 26 * An input stream that can have the close operation disabled (to avoid 27 * accidentally being closed). This is necessary, for example, when an input 28 * stream needs to be marked-and-reset multiple times but only as long as the 29 * input stream has not been closed. To survive not being accidentally closed, 30 * the close method can be disabled via {@link #disableClose()}. 31 * <p> 32 * The creator of this input stream should therefore always call 33 * {@link #release()} in a finally block to truly release the underlying 34 * resources. 35 * 36 * @see Releasable 37 * @see ResettableInputStream 38 */ 39 @NotThreadSafe 40 @SdkProtectedApi 41 public class ReleasableInputStream extends SdkFilterInputStream { 42 private static final Logger log = Logger.loggerFor(ReleasableInputStream.class); 43 /** 44 * True if the close method is disabled; false otherwise. Default is false. 45 * In case the close method is disabled, caller would be responsible to 46 * release resources via {@link #release()}. 47 */ 48 private boolean closeDisabled; 49 50 /** 51 * This constructor is not meant to be used directly. Use 52 * {@link #wrap(InputStream)} instead. 53 */ ReleasableInputStream(InputStream is)54 protected ReleasableInputStream(InputStream is) { 55 super(is); 56 } 57 58 /** 59 * Wraps the given input stream into a {@link ReleasableInputStream} if 60 * necessary. Note if the given input stream is a {@link FileInputStream}, a 61 * {@link ResettableInputStream} which is a specific subclass of 62 * {@link ReleasableInputStream} will be returned. 63 */ wrap(InputStream is)64 public static ReleasableInputStream wrap(InputStream is) { 65 if (is instanceof ReleasableInputStream) { 66 return (ReleasableInputStream) is; // already wrapped 67 } 68 if (is instanceof FileInputStream) { 69 return ResettableInputStream.newResettableInputStream((FileInputStream) is); 70 } 71 return new ReleasableInputStream(is); 72 } 73 74 /** 75 * If {@link #closeDisabled} is false, closes this input stream and releases 76 * any system resources associated with the stream. Otherwise, this method 77 * does nothing. 78 */ 79 @Override close()80 public final void close() { 81 if (!closeDisabled) { 82 doRelease(); 83 } 84 } 85 86 /** 87 * Closes the underlying stream file and releases any system resources associated. 88 */ 89 @Override release()90 public final void release() { 91 doRelease(); 92 } 93 94 /** 95 * Used to truly release the underlying resources. 96 */ doRelease()97 private void doRelease() { 98 try { 99 in.close(); 100 } catch (Exception ex) { 101 log.debug(() -> "Ignore failure in closing the input stream", ex); 102 } 103 if (in instanceof Releasable) { 104 // This allows any underlying stream that has the close operation 105 // disabled to be truly released 106 Releasable r = (Releasable) in; 107 r.release(); 108 } 109 abortIfNeeded(); 110 } 111 112 /** 113 * Returns true if the close method has been disabled; false otherwise. Once 114 * the close method is disabled, caller would be responsible to release 115 * resources via {@link #release()}. 116 */ isCloseDisabled()117 public final boolean isCloseDisabled() { 118 return closeDisabled; 119 } 120 121 /** 122 * Used to disable the close method. Once the close method is disabled, 123 * caller would be responsible to release resources via {@link #release()}. 124 */ disableClose()125 public final <T extends ReleasableInputStream> T disableClose() { 126 this.closeDisabled = true; 127 @SuppressWarnings("unchecked") 128 T t = (T) this; 129 return t; 130 } 131 } 132