• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Guava Authors
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  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.io.SourceSinkFactory.ByteSinkFactory;
21 import static com.google.common.io.SourceSinkFactory.ByteSourceFactory;
22 import static com.google.common.io.SourceSinkFactory.CharSinkFactory;
23 import static com.google.common.io.SourceSinkFactory.CharSourceFactory;
24 
25 import com.google.common.base.Charsets;
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33 import java.io.OutputStream;
34 import java.io.OutputStreamWriter;
35 import java.io.Reader;
36 import java.io.Writer;
37 import java.nio.CharBuffer;
38 import java.util.Arrays;
39 import java.util.logging.Logger;
40 import org.checkerframework.checker.nullness.compatqual.NullableDecl;
41 
42 /**
43  * {@link SourceSinkFactory} implementations.
44  *
45  * @author Colin Decker
46  */
47 public class SourceSinkFactories {
48 
SourceSinkFactories()49   private SourceSinkFactories() {}
50 
stringCharSourceFactory()51   public static CharSourceFactory stringCharSourceFactory() {
52     return new StringSourceFactory();
53   }
54 
byteArraySourceFactory()55   public static ByteSourceFactory byteArraySourceFactory() {
56     return new ByteArraySourceFactory();
57   }
58 
emptyByteSourceFactory()59   public static ByteSourceFactory emptyByteSourceFactory() {
60     return new EmptyByteSourceFactory();
61   }
62 
emptyCharSourceFactory()63   public static CharSourceFactory emptyCharSourceFactory() {
64     return new EmptyCharSourceFactory();
65   }
66 
fileByteSourceFactory()67   public static ByteSourceFactory fileByteSourceFactory() {
68     return new FileByteSourceFactory();
69   }
70 
fileByteSinkFactory()71   public static ByteSinkFactory fileByteSinkFactory() {
72     return new FileByteSinkFactory(null);
73   }
74 
appendingFileByteSinkFactory()75   public static ByteSinkFactory appendingFileByteSinkFactory() {
76     String initialString = IoTestCase.ASCII + IoTestCase.I18N;
77     return new FileByteSinkFactory(initialString.getBytes(Charsets.UTF_8));
78   }
79 
fileCharSourceFactory()80   public static CharSourceFactory fileCharSourceFactory() {
81     return new FileCharSourceFactory();
82   }
83 
fileCharSinkFactory()84   public static CharSinkFactory fileCharSinkFactory() {
85     return new FileCharSinkFactory(null);
86   }
87 
appendingFileCharSinkFactory()88   public static CharSinkFactory appendingFileCharSinkFactory() {
89     String initialString = IoTestCase.ASCII + IoTestCase.I18N;
90     return new FileCharSinkFactory(initialString);
91   }
92 
urlByteSourceFactory()93   public static ByteSourceFactory urlByteSourceFactory() {
94     return new UrlByteSourceFactory();
95   }
96 
urlCharSourceFactory()97   public static CharSourceFactory urlCharSourceFactory() {
98     return new UrlCharSourceFactory();
99   }
100 
asByteSourceFactory(final CharSourceFactory factory)101   public static ByteSourceFactory asByteSourceFactory(final CharSourceFactory factory) {
102     checkNotNull(factory);
103     return new ByteSourceFactory() {
104       @Override
105       public ByteSource createSource(byte[] data) throws IOException {
106         return factory.createSource(new String(data, Charsets.UTF_8)).asByteSource(Charsets.UTF_8);
107       }
108 
109       @Override
110       public byte[] getExpected(byte[] data) {
111         return factory.getExpected(new String(data, Charsets.UTF_8)).getBytes(Charsets.UTF_8);
112       }
113 
114       @Override
115       public void tearDown() throws IOException {
116         factory.tearDown();
117       }
118     };
119   }
120 
121   public static CharSourceFactory asCharSourceFactory(final ByteSourceFactory factory) {
122     checkNotNull(factory);
123     return new CharSourceFactory() {
124       @Override
125       public CharSource createSource(String string) throws IOException {
126         return factory.createSource(string.getBytes(Charsets.UTF_8)).asCharSource(Charsets.UTF_8);
127       }
128 
129       @Override
130       public String getExpected(String data) {
131         return new String(factory.getExpected(data.getBytes(Charsets.UTF_8)), Charsets.UTF_8);
132       }
133 
134       @Override
135       public void tearDown() throws IOException {
136         factory.tearDown();
137       }
138     };
139   }
140 
141   public static CharSinkFactory asCharSinkFactory(final ByteSinkFactory factory) {
142     checkNotNull(factory);
143     return new CharSinkFactory() {
144       @Override
145       public CharSink createSink() throws IOException {
146         return factory.createSink().asCharSink(Charsets.UTF_8);
147       }
148 
149       @Override
150       public String getSinkContents() throws IOException {
151         return new String(factory.getSinkContents(), Charsets.UTF_8);
152       }
153 
154       @Override
155       public String getExpected(String data) {
156         /*
157          * Get what the byte sink factory would expect for no written bytes, then append expected
158          * string to that.
159          */
160         byte[] factoryExpectedForNothing = factory.getExpected(new byte[0]);
161         return new String(factoryExpectedForNothing, Charsets.UTF_8) + checkNotNull(data);
162       }
163 
164       @Override
165       public void tearDown() throws IOException {
166         factory.tearDown();
167       }
168     };
169   }
170 
171   public static ByteSourceFactory asSlicedByteSourceFactory(
172       final ByteSourceFactory factory, final long off, final long len) {
173     checkNotNull(factory);
174     return new ByteSourceFactory() {
175       @Override
176       public ByteSource createSource(byte[] bytes) throws IOException {
177         return factory.createSource(bytes).slice(off, len);
178       }
179 
180       @Override
181       public byte[] getExpected(byte[] bytes) {
182         byte[] baseExpected = factory.getExpected(bytes);
183         int startOffset = (int) Math.min(off, baseExpected.length);
184         int actualLen = (int) Math.min(len, baseExpected.length - startOffset);
185         return Arrays.copyOfRange(baseExpected, startOffset, startOffset + actualLen);
186       }
187 
188       @Override
189       public void tearDown() throws IOException {
190         factory.tearDown();
191       }
192     };
193   }
194 
195   private static class StringSourceFactory implements CharSourceFactory {
196 
197     @Override
198     public CharSource createSource(String data) throws IOException {
199       return CharSource.wrap(data);
200     }
201 
202     @Override
203     public String getExpected(String data) {
204       return data;
205     }
206 
207     @Override
208     public void tearDown() throws IOException {}
209   }
210 
211   private static class ByteArraySourceFactory implements ByteSourceFactory {
212 
213     @Override
214     public ByteSource createSource(byte[] bytes) throws IOException {
215       return ByteSource.wrap(bytes);
216     }
217 
218     @Override
219     public byte[] getExpected(byte[] bytes) {
220       return bytes;
221     }
222 
223     @Override
224     public void tearDown() throws IOException {}
225   }
226 
227   private static class EmptyCharSourceFactory implements CharSourceFactory {
228 
229     @Override
230     public CharSource createSource(String data) throws IOException {
231       return CharSource.empty();
232     }
233 
234     @Override
235     public String getExpected(String data) {
236       return "";
237     }
238 
239     @Override
240     public void tearDown() throws IOException {}
241   }
242 
243   private static class EmptyByteSourceFactory implements ByteSourceFactory {
244 
245     @Override
246     public ByteSource createSource(byte[] bytes) throws IOException {
247       return ByteSource.empty();
248     }
249 
250     @Override
251     public byte[] getExpected(byte[] bytes) {
252       return new byte[0];
253     }
254 
255     @Override
256     public void tearDown() throws IOException {}
257   }
258 
259   private abstract static class FileFactory {
260 
261     private static final Logger logger = Logger.getLogger(FileFactory.class.getName());
262 
263     private final ThreadLocal<File> fileThreadLocal = new ThreadLocal<>();
264 
265     protected File createFile() throws IOException {
266       File file = File.createTempFile("SinkSourceFile", "txt");
267       fileThreadLocal.set(file);
268       return file;
269     }
270 
271     protected File getFile() {
272       return fileThreadLocal.get();
273     }
274 
275     public final void tearDown() throws IOException {
276       if (!fileThreadLocal.get().delete()) {
277         logger.warning("Unable to delete file: " + fileThreadLocal.get());
278       }
279       fileThreadLocal.remove();
280     }
281   }
282 
283   private static class FileByteSourceFactory extends FileFactory implements ByteSourceFactory {
284 
285     @Override
286     public ByteSource createSource(byte[] bytes) throws IOException {
287       checkNotNull(bytes);
288       File file = createFile();
289       OutputStream out = new FileOutputStream(file);
290       try {
291         out.write(bytes);
292       } finally {
293         out.close();
294       }
295       return Files.asByteSource(file);
296     }
297 
298     @Override
299     public byte[] getExpected(byte[] bytes) {
300       return checkNotNull(bytes);
301     }
302   }
303 
304   private static class FileByteSinkFactory extends FileFactory implements ByteSinkFactory {
305 
306     private final byte[] initialBytes;
307 
308     private FileByteSinkFactory(@NullableDecl byte[] initialBytes) {
309       this.initialBytes = initialBytes;
310     }
311 
312     @Override
313     public ByteSink createSink() throws IOException {
314       File file = createFile();
315       if (initialBytes != null) {
316         FileOutputStream out = new FileOutputStream(file);
317         try {
318           out.write(initialBytes);
319         } finally {
320           out.close();
321         }
322         return Files.asByteSink(file, FileWriteMode.APPEND);
323       }
324       return Files.asByteSink(file);
325     }
326 
327     @Override
328     public byte[] getExpected(byte[] bytes) {
329       if (initialBytes == null) {
330         return checkNotNull(bytes);
331       } else {
332         byte[] result = new byte[initialBytes.length + bytes.length];
333         System.arraycopy(initialBytes, 0, result, 0, initialBytes.length);
334         System.arraycopy(bytes, 0, result, initialBytes.length, bytes.length);
335         return result;
336       }
337     }
338 
339     @Override
340     public byte[] getSinkContents() throws IOException {
341       File file = getFile();
342       InputStream in = new FileInputStream(file);
343       ByteArrayOutputStream out = new ByteArrayOutputStream();
344       byte[] buffer = new byte[100];
345       int read;
346       while ((read = in.read(buffer)) != -1) {
347         out.write(buffer, 0, read);
348       }
349       return out.toByteArray();
350     }
351   }
352 
353   private static class FileCharSourceFactory extends FileFactory implements CharSourceFactory {
354 
355     @Override
356     public CharSource createSource(String string) throws IOException {
357       checkNotNull(string);
358       File file = createFile();
359       Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8);
360       try {
361         writer.write(string);
362       } finally {
363         writer.close();
364       }
365       return Files.asCharSource(file, Charsets.UTF_8);
366     }
367 
368     @Override
369     public String getExpected(String string) {
370       return checkNotNull(string);
371     }
372   }
373 
374   private static class FileCharSinkFactory extends FileFactory implements CharSinkFactory {
375 
376     private final String initialString;
377 
378     private FileCharSinkFactory(@NullableDecl String initialString) {
379       this.initialString = initialString;
380     }
381 
382     @Override
383     public CharSink createSink() throws IOException {
384       File file = createFile();
385       if (initialString != null) {
386         Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8);
387         try {
388           writer.write(initialString);
389         } finally {
390           writer.close();
391         }
392         return Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND);
393       }
394       return Files.asCharSink(file, Charsets.UTF_8);
395     }
396 
397     @Override
398     public String getExpected(String string) {
399       checkNotNull(string);
400       return initialString == null ? string : initialString + string;
401     }
402 
403     @Override
404     public String getSinkContents() throws IOException {
405       File file = getFile();
406       Reader reader = new InputStreamReader(new FileInputStream(file), Charsets.UTF_8);
407       StringBuilder builder = new StringBuilder();
408       CharBuffer buffer = CharBuffer.allocate(100);
409       while (reader.read(buffer) != -1) {
410         buffer.flip();
411         builder.append(buffer);
412         buffer.clear();
413       }
414       return builder.toString();
415     }
416   }
417 
418   private static class UrlByteSourceFactory extends FileByteSourceFactory {
419 
420     @SuppressWarnings("CheckReturnValue") // only using super.createSource to create a file
421     @Override
422     public ByteSource createSource(byte[] bytes) throws IOException {
423       super.createSource(bytes);
424       return Resources.asByteSource(getFile().toURI().toURL());
425     }
426   }
427 
428   private static class UrlCharSourceFactory extends FileCharSourceFactory {
429 
430     @SuppressWarnings("CheckReturnValue") // only using super.createSource to create a file
431     @Override
432     public CharSource createSource(String string) throws IOException {
433       super.createSource(string); // just ignore returned CharSource
434       return Resources.asCharSource(getFile().toURI().toURL(), Charsets.UTF_8);
435     }
436   }
437 }
438