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