1cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath/*
2cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  Licensed to the Apache Software Foundation (ASF) under one or more
3cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  contributor license agreements.  See the NOTICE file distributed with
4cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  this work for additional information regarding copyright ownership.
5cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  The ASF licenses this file to You under the Apache License, Version 2.0
6cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  (the "License"); you may not use this file except in compliance with
7cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  the License.  You may obtain a copy of the License at
8cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *
9cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *     http://www.apache.org/licenses/LICENSE-2.0
10cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *
11cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  Unless required by applicable law or agreed to in writing, software
12cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  distributed under the License is distributed on an "AS IS" BASIS,
13cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  See the License for the specific language governing permissions and
15cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath *  limitations under the License.
16cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath */
17cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
18cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathpackage org.apache.harmony.testframework;
19cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
20cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathimport junit.framework.TestCase;
21cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathimport junit.framework.TestSuite;
22cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
23cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathimport java.io.ByteArrayOutputStream;
24cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathimport java.io.IOException;
25cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathimport java.io.OutputStream;
26cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
27cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath/**
28cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath * Tests behaviour common to wrapping and filtering implementations of {@link
29cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath * OutputStream}.
30cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath */
31cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamathpublic abstract class WrapperTester {
32cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
33cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    private boolean throwsExceptions = true;
34cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
35cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    /**
36cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * Creates a new output stream that receives one stream of bytes, optionally
37cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * transforms it, and emits another stream of bytes to {@code delegate}.
38cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     */
39cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public abstract OutputStream create(OutputStream delegate) throws Exception;
40cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
41cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    /**
42cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * Decodes the bytes received by the delegate into their original form: the
43cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * bytes originally received by this wrapper.
44cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     */
45cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public abstract byte[] decode(byte[] delegateBytes) throws Exception;
46cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
47cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    /**
48cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * Configures whether the stream is expected to throw exceptions when an
49cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * error is encountered. Classes like {@code PrintStream} report errors via
50cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     * an API method instead.
51cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath     */
52cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public WrapperTester setThrowsExceptions(boolean throwsExceptions) {
53cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        this.throwsExceptions = throwsExceptions;
54cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        return this;
55cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
56cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
57cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public final TestSuite createTests() {
58cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        TestSuite result = new TestSuite();
59cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        result.addTest(new WrapperSinkTester()
60cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                .setThrowsExceptions(throwsExceptions)
61cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                .createTests());
62cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
63cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        if (throwsExceptions) {
64cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlush"));
65cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaClose"));
66cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestCloseThrows"));
67cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        } else {
68cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlushSuppressed"));
69cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaCloseSuppressed"));
70cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            result.addTest(new WrapperTestCase("wrapperTestCloseThrowsSuppressed"));
71cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
72cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
73cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        return result;
74cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
75cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
76cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    @Override
77cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public String toString() {
78cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        return getClass().getName();
79cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
80cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
81cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    private class WrapperSinkTester extends SinkTester {
82cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        private ClosableByteArrayOutputStream delegate;
83cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
84cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
85cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public OutputStream create() throws Exception {
86cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            delegate = new ClosableByteArrayOutputStream();
87cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            return WrapperTester.this.create(delegate);
88cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
89cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
90cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
91cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public byte[] getBytes() throws Exception {
92cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            return WrapperTester.this.decode(delegate.bytesOut.toByteArray());
93cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
94cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
95cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
96cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public String toString() {
97cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            return WrapperTester.this.toString();
98cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
99cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
100cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
101cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    public class WrapperTestCase extends TestCase {
102cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
103cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        private WrapperTestCase(String name) {
104cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            super(name);
105cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
106cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
107cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
108cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public String getName() {
109cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            return WrapperTester.this.toString() + ":" + super.getName();
110cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
111cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
112cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestFlushThrowsViaFlushSuppressed() throws Exception {
113cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
114cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
115cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.write(new byte[] { 8, 6, 7, 5 });
116cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.write(new byte[] { 3, 0, 9 });
117cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.flush();
118cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            assertTrue(delegate.flushed);
119cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
120cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
121cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestFlushThrowsViaCloseSuppressed() throws Exception {
122cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
123cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
124cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.write(new byte[] { 8, 6, 7, 5 });
125cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.write(new byte[] { 3, 0, 9 });
126cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.close();
127cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            assertTrue(delegate.flushed);
128cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
129cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
130cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestFlushThrowsViaFlush() throws Exception {
131cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
132cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
133cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
134cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            try {
135cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                // any of these is permitted to flush
136cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.write(new byte[] { 8, 6, 7, 5 });
137cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.write(new byte[] { 3, 0, 9 });
138cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.flush();
139cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertTrue(delegate.flushed);
140cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                fail("flush exception ignored");
141cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            } catch (IOException expected) {
142cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertEquals("Flush failed", expected.getMessage());
143cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
144cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
145cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
146cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestFlushThrowsViaClose() throws Exception {
147cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
148cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
149cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
150cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            try {
151cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                // any of these is permitted to flush
152cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.write(new byte[] { 8, 6, 7, 5 });
153cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.write(new byte[] { 3, 0, 9 });
154cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.close();
155cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertTrue(delegate.flushed);
156cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                fail("flush exception ignored");
157cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            } catch (IOException expected) {
158cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertEquals("Flush failed", expected.getMessage());
159cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
160cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
161cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            try {
162cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.write(new byte[] { 4, 4, 5 });
163cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                fail("expected already closed exception");
164cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            } catch (IOException expected) {
165cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
166cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
167cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
168cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestCloseThrows() throws Exception {
169cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
170cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
171cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            try {
172cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                o.close();
173cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertTrue(delegate.closed);
174cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                fail("close exception ignored");
175cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            } catch (IOException expected) {
176cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                assertEquals("Close failed", expected.getMessage());
177cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
178cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
179cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
180cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void wrapperTestCloseThrowsSuppressed() throws Exception {
181cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
182cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            OutputStream o = create(delegate);
183cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            o.close();
184cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            assertTrue(delegate.closed);
185cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
186cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
187cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        // adding a new test? Don't forget to update createTests().
188cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
189cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
190cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    private static class ClosableByteArrayOutputStream extends OutputStream {
191cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        private final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
192cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        private boolean closed = false;
193cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
194cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
195cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void close() throws IOException {
196cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            closed = true;
197cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
198cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
199cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
200cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void write(int oneByte) throws IOException {
201cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            if (closed) {
202cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                throw new IOException();
203cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
204cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            bytesOut.write(oneByte);
205cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
206cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
207cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
208cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    private static class FailOnFlushOutputStream extends OutputStream {
209cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        boolean flushed = false;
210cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        boolean closed = false;
211cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
212cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
213cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void write(int oneByte) throws IOException {
214cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            if (closed) {
215cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                throw new IOException("Already closed");
216cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
217cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
218cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
219cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
220cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void close() throws IOException {
221cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            closed = true;
222cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            flush();
223cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
224cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
225cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
226cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void flush() throws IOException {
227cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            if (!flushed) {
228cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                flushed = true;
229cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath                throw new IOException("Flush failed");
230cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            }
231cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
232cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
233cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
234cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    private static class FailOnCloseOutputStream extends ByteArrayOutputStream {
235cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        boolean closed = false;
236cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath
237cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        @Override
238cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        public void close() throws IOException {
239cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            closed = true;
240cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath            throw new IOException("Close failed");
241cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath        }
242cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath    }
243cb318c6f4fe5b0e20099fa85f1b95ccb2d24119fNarayan Kamath}
244