1 /*
2  * Copyright 2013-2020 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 package com.amazonaws.internal;
16
17 import static com.amazonaws.util.SdkRuntime.shouldAbort;
18
19 import com.amazonaws.AbortedException;
20 import com.amazonaws.annotation.SdkProtectedApi;
21 import java.io.FilterInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24
25 /**
26  * Base class for AWS Java SDK specific {@link FilterInputStream}.
27  */

28 public class SdkFilterInputStream extends FilterInputStream implements
29         MetricAware, Releasable {
30     private volatile boolean aborted = false;
31
32     protected SdkFilterInputStream(InputStream in) {
33         super(in);
34     }
35
36     /**
37      * @return The wrapped stream.
38      */

39     @SdkProtectedApi
40     public InputStream getDelegateStream() {
41         return in;
42     }
43
44     @Override
45     public boolean isMetricActivated() {
46         if (in instanceof MetricAware) {
47             MetricAware metricAware = (MetricAware)in;
48             return metricAware.isMetricActivated();
49         }
50         return false;
51     }
52
53     /**
54      * Aborts with subclass specific abortion logic executed if needed.
55      * Note the interrupted status of the thread is cleared by this method.
56      * @throws AbortedException if found necessary.
57      */

58     protected final void abortIfNeeded() {
59         if (shouldAbort()) {
60             abort();    // execute subclass specific abortion logic
61             throw new AbortedException();
62         }
63     }
64
65     /**
66      * Can be used to provide abortion logic prior to throwing the
67      * AbortedException. If the wrapped {@code InputStream} is also an instance
68      * of this class, then it will also be aborted, otherwise this is a no-op.
69      */

70     public void abort() {
71         if (in instanceof SdkFilterInputStream) {
72             ((SdkFilterInputStream) in).abort();
73         }
74         aborted = true;
75     }
76
77     protected boolean isAborted() {
78         return aborted;
79     }
80
81     @Override
82     public int read() throws IOException {
83         abortIfNeeded();
84         return in.read();
85     }
86
87     @Override
88     public int read(byte b[], int off, int len) throws IOException {
89         abortIfNeeded();
90         return in.read(b, off, len);
91     }
92
93     @Override
94     public long skip(long n) throws IOException {
95         abortIfNeeded();
96         return in.skip(n);
97     }
98
99     @Override
100     public int available() throws IOException {
101         abortIfNeeded();
102         return in.available();
103     }
104
105     @Override
106     public void close() throws IOException {
107         in.close();
108         abortIfNeeded();
109     }
110
111     @Override
112     public synchronized void mark(int readlimit) {
113         abortIfNeeded();
114         in.mark(readlimit);
115     }
116
117     @Override
118     public synchronized void reset() throws IOException {
119         abortIfNeeded();
120         in.reset();
121     }
122
123     @Override
124     public boolean markSupported() {
125         abortIfNeeded();
126         return in.markSupported();
127     }
128
129     @Override
130     public void release() {
131         // Don't call IOUtils.release(in, null) or else could lead to infinite loop
132         SdkIOUtils.closeQuietly(this);
133         if (in instanceof Releasable) {
134             // This allows any underlying stream that has the close operation
135             // disabled to be truly released
136             Releasable r = (Releasable)in;
137             r.release();
138         }
139     }
140 }
141