1 /*
2  * Copyright (C) 2006 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.io;
16 
17 import static com.google.common.base.Preconditions.checkNotNull;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import java.io.Closeable;
21 import java.io.Flushable;
22 import java.io.IOException;
23 import java.io.Writer;
24 import org.checkerframework.checker.nullness.qual.Nullable;
25 
26 /**
27  * Writer that places all output on an {@link Appendable} target. If the target is {@link Flushable}
28  * or {@link Closeable}, flush()es and close()s will also be delegated to the target.
29  *
30  * @author Alan Green
31  * @author Sebastian Kanthak
32  * @since 1.0
33  */
34 @GwtIncompatible
35 class AppendableWriter extends Writer {
36   private final Appendable target;
37   private boolean closed;
38 
39   /**
40    * Creates a new writer that appends everything it writes to {@code target}.
41    *
42    * @param target target to which to append output
43    */
AppendableWriter(Appendable target)44   AppendableWriter(Appendable target) {
45     this.target = checkNotNull(target);
46   }
47 
48   /*
49    * Abstract methods from Writer
50    */
51 
52   @Override
write(char[] cbuf, int off, int len)53   public void write(char[] cbuf, int off, int len) throws IOException {
54     checkNotClosed();
55     // It turns out that creating a new String is usually as fast, or faster
56     // than wrapping cbuf in a light-weight CharSequence.
57     target.append(new String(cbuf, off, len));
58   }
59 
60   /*
61    * Override a few functions for performance reasons to avoid creating unnecessary strings.
62    */
63 
64   @Override
write(int c)65   public void write(int c) throws IOException {
66     checkNotClosed();
67     target.append((char) c);
68   }
69 
70   @Override
write(@ullable String str)71   public void write(@Nullable String str) throws IOException {
72     checkNotClosed();
73     target.append(str);
74   }
75 
76   @Override
write(@ullable String str, int off, int len)77   public void write(@Nullable String str, int off, int len) throws IOException {
78     checkNotClosed();
79     // tricky: append takes start, end pair...
80     target.append(str, off, off + len);
81   }
82 
83   @Override
flush()84   public void flush() throws IOException {
85     checkNotClosed();
86     if (target instanceof Flushable) {
87       ((Flushable) target).flush();
88     }
89   }
90 
91   @Override
close()92   public void close() throws IOException {
93     this.closed = true;
94     if (target instanceof Closeable) {
95       ((Closeable) target).close();
96     }
97   }
98 
99   @Override
append(char c)100   public Writer append(char c) throws IOException {
101     checkNotClosed();
102     target.append(c);
103     return this;
104   }
105 
106   @Override
append(@ullable CharSequence charSeq)107   public Writer append(@Nullable CharSequence charSeq) throws IOException {
108     checkNotClosed();
109     target.append(charSeq);
110     return this;
111   }
112 
113   @Override
append(@ullable CharSequence charSeq, int start, int end)114   public Writer append(@Nullable CharSequence charSeq, int start, int end) throws IOException {
115     checkNotClosed();
116     target.append(charSeq, start, end);
117     return this;
118   }
119 
checkNotClosed()120   private void checkNotClosed() throws IOException {
121     if (closed) {
122       throw new IOException("Cannot write to a closed writer.");
123     }
124   }
125 }
126