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