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 SourceSinkFactories()52 private SourceSinkFactories() {} 53 stringCharSourceFactory()54 public static CharSourceFactory stringCharSourceFactory() { 55 return new StringSourceFactory(); 56 } 57 byteArraySourceFactory()58 public static ByteSourceFactory byteArraySourceFactory() { 59 return new ByteArraySourceFactory(); 60 } 61 emptyByteSourceFactory()62 public static ByteSourceFactory emptyByteSourceFactory() { 63 return new EmptyByteSourceFactory(); 64 } 65 emptyCharSourceFactory()66 public static CharSourceFactory emptyCharSourceFactory() { 67 return new EmptyCharSourceFactory(); 68 } 69 fileByteSourceFactory()70 public static ByteSourceFactory fileByteSourceFactory() { 71 return new FileByteSourceFactory(); 72 } 73 fileByteSinkFactory()74 public static ByteSinkFactory fileByteSinkFactory() { 75 return new FileByteSinkFactory(null); 76 } 77 appendingFileByteSinkFactory()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 fileCharSourceFactory()87 public static CharSourceFactory fileCharSourceFactory() { 88 return new FileCharSourceFactory(); 89 } 90 fileCharSinkFactory()91 public static CharSinkFactory fileCharSinkFactory() { 92 return new FileCharSinkFactory(null); 93 } 94 appendingFileCharSinkFactory()95 public static CharSinkFactory appendingFileCharSinkFactory() { 96 String initialString = IoTestCase.ASCII + IoTestCase.I18N; 97 return new FileCharSinkFactory(initialString); 98 } 99 urlByteSourceFactory()100 public static ByteSourceFactory urlByteSourceFactory() { 101 return new UrlByteSourceFactory(); 102 } 103 urlCharSourceFactory()104 public static CharSourceFactory urlCharSourceFactory() { 105 return new UrlCharSourceFactory(); 106 } 107 asCharSourceFactory(final ByteSourceFactory factory)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