001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.io.build; 019 020import java.io.File; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.io.Reader; 025import java.io.Writer; 026import java.net.URI; 027import java.nio.charset.Charset; 028import java.nio.file.Files; 029import java.nio.file.OpenOption; 030import java.nio.file.Path; 031import java.nio.file.Paths; 032import java.util.Objects; 033 034/** 035 * Abstracts the origin of data for builders like a {@link File}, {@link Path}, {@link Reader}, {@link Writer}, {@link InputStream}, {@link OutputStream}, and 036 * {@link URI}. 037 * <p> 038 * Some methods may throw {@link UnsupportedOperationException} if that method is not implemented in a concrete subclass, see {@link #getFile()} and 039 * {@link #getPath()}. 040 * </p> 041 * 042 * @param <T> the type of instances to build. 043 * @param <B> the type of builder subclass. 044 * @since 2.12.0 045 */ 046public abstract class AbstractOrigin<T, B extends AbstractOrigin<T, B>> extends AbstractSupplier<T, B> { 047 048 /** 049 * A {@link File} origin. 050 */ 051 public static class ByteArrayOrigin extends AbstractOrigin<byte[], ByteArrayOrigin> { 052 053 /** 054 * Constructs a new instance for the given origin. 055 * 056 * @param origin The origin. 057 */ 058 public ByteArrayOrigin(final byte[] origin) { 059 super(origin); 060 } 061 062 @Override 063 public byte[] getByteArray() { 064 // No conversion 065 return get(); 066 } 067 068 } 069 070 /** 071 * A {@link File} origin. 072 * <p> 073 * Starting from this origin, you can get a byte array, a file, an input stream, an output stream, a path, a reader, and a writer. 074 * </p> 075 */ 076 public static class FileOrigin extends AbstractOrigin<File, FileOrigin> { 077 078 /** 079 * Constructs a new instance for the given origin. 080 * 081 * @param origin The origin. 082 */ 083 public FileOrigin(final File origin) { 084 super(origin); 085 } 086 087 @Override 088 public File getFile() { 089 // No conversion 090 return get(); 091 } 092 093 @Override 094 public Path getPath() { 095 return get().toPath(); 096 } 097 098 } 099 100 /** 101 * An {@link InputStream} origin. 102 * <p> 103 * This origin cannot provide other aspects. 104 * </p> 105 */ 106 public static class InputStreamOrigin extends AbstractOrigin<InputStream, InputStreamOrigin> { 107 108 /** 109 * Constructs a new instance for the given origin. 110 * 111 * @param origin The origin. 112 */ 113 public InputStreamOrigin(final InputStream origin) { 114 super(origin); 115 } 116 117 @Override 118 public InputStream getInputStream(final OpenOption... options) { 119 // No conversion 120 return get(); 121 } 122 123 } 124 125 /** 126 * An {@link OutputStream} origin. 127 * <p> 128 * This origin cannot provide other aspects. 129 * </p> 130 */ 131 public static class OutputStreamOrigin extends AbstractOrigin<OutputStream, OutputStreamOrigin> { 132 133 /** 134 * Constructs a new instance for the given origin. 135 * 136 * @param origin The origin. 137 */ 138 public OutputStreamOrigin(final OutputStream origin) { 139 super(origin); 140 } 141 142 @Override 143 public OutputStream getOutputStream(final OpenOption... options) { 144 // No conversion 145 return get(); 146 } 147 148 } 149 150 /** 151 * A {@link Path} origin. 152 * <p> 153 * Starting from this origin, you can get a byte array, a file, an input stream, an output stream, a path, a reader, and a writer. 154 * </p> 155 */ 156 public static class PathOrigin extends AbstractOrigin<Path, PathOrigin> { 157 158 /** 159 * Constructs a new instance for the given origin. 160 * 161 * @param origin The origin. 162 */ 163 public PathOrigin(final Path origin) { 164 super(origin); 165 } 166 167 @Override 168 public File getFile() { 169 return get().toFile(); 170 } 171 172 @Override 173 public Path getPath() { 174 // No conversion 175 return get(); 176 } 177 178 } 179 180 /** 181 * An {@link Reader} origin. 182 * <p> 183 * This origin cannot provide other aspects. 184 * </p> 185 */ 186 public static class ReaderOrigin extends AbstractOrigin<Reader, ReaderOrigin> { 187 188 /** 189 * Constructs a new instance for the given origin. 190 * 191 * @param origin The origin. 192 */ 193 public ReaderOrigin(final Reader origin) { 194 super(origin); 195 } 196 197 @Override 198 public Reader getReader(final Charset charset) throws IOException { 199 // No conversion 200 return get(); 201 } 202 } 203 204 /** 205 * A {@link URI} origin. 206 */ 207 public static class URIOrigin extends AbstractOrigin<URI, URIOrigin> { 208 209 /** 210 * Constructs a new instance for the given origin. 211 * 212 * @param origin The origin. 213 */ 214 public URIOrigin(final URI origin) { 215 super(origin); 216 } 217 218 @Override 219 public File getFile() { 220 return getPath().toFile(); 221 } 222 223 @Override 224 public Path getPath() { 225 return Paths.get(get()); 226 } 227 228 } 229 230 /** 231 * An {@link Writer} origin. 232 * <p> 233 * This origin cannot provide other aspects. 234 * </p> 235 */ 236 public static class WriterOrigin extends AbstractOrigin<Writer, WriterOrigin> { 237 238 /** 239 * Constructs a new instance for the given origin. 240 * 241 * @param origin The origin. 242 */ 243 public WriterOrigin(final Writer origin) { 244 super(origin); 245 } 246 247 @Override 248 public Writer getWriter(final Charset charset, final OpenOption... options) throws IOException { 249 // No conversion 250 return get(); 251 } 252 } 253 254 /** 255 * The non-null origin. 256 */ 257 final T origin; 258 259 /** 260 * Constructs a new instance for a subclass. 261 * 262 * @param origin The origin. 263 */ 264 protected AbstractOrigin(final T origin) { 265 this.origin = Objects.requireNonNull(origin, "origin"); 266 } 267 268 /** 269 * Gets the origin. 270 * 271 * @return the origin. 272 */ 273 @Override 274 public T get() { 275 return origin; 276 } 277 278 /** 279 * Gets this origin as a byte array, if possible. 280 * 281 * @return this origin as a byte array, if possible. 282 * @throws IOException if an I/O error occurs. 283 * @throws UnsupportedOperationException if the origin cannot be converted to a Path. 284 */ 285 public byte[] getByteArray() throws IOException { 286 return Files.readAllBytes(getPath()); 287 } 288 289 /** 290 * Gets this origin as a Path, if possible. 291 * 292 * @return this origin as a Path, if possible. 293 * @throws UnsupportedOperationException if this method is not implemented in a concrete subclass. 294 */ 295 public File getFile() { 296 throw new UnsupportedOperationException(origin.toString()); 297 } 298 299 /** 300 * Gets this origin as an InputStream, if possible. 301 * 302 * @param options options specifying how the file is opened 303 * @return this origin as an InputStream, if possible. 304 * @throws IOException if an I/O error occurs. 305 * @throws UnsupportedOperationException if the origin cannot be converted to a Path. 306 */ 307 public InputStream getInputStream(final OpenOption... options) throws IOException { 308 return Files.newInputStream(getPath(), options); 309 } 310 311 /** 312 * Gets this origin as an OutputStream, if possible. 313 * 314 * @param options options specifying how the file is opened 315 * @return this origin as an OutputStream, if possible. 316 * @throws IOException if an I/O error occurs. 317 * @throws UnsupportedOperationException if the origin cannot be converted to a Path. 318 */ 319 public OutputStream getOutputStream(final OpenOption... options) throws IOException { 320 return Files.newOutputStream(getPath(), options); 321 } 322 323 /** 324 * Gets this origin as a Path, if possible. 325 * 326 * @return this origin as a Path, if possible. 327 * @throws UnsupportedOperationException if this method is not implemented in a concrete subclass. 328 */ 329 public Path getPath() { 330 throw new UnsupportedOperationException(origin.toString()); 331 } 332 333 /** 334 * Gets a new Reader on the origin, buffered by default. 335 * 336 * @param charset the charset to use for decoding 337 * @return a new Reader on the origin. 338 * @throws IOException if an I/O error occurs opening the file. 339 */ 340 public Reader getReader(final Charset charset) throws IOException { 341 return Files.newBufferedReader(getPath(), charset); 342 } 343 344 /** 345 * Gets a new Writer on the origin, buffered by default. 346 * 347 * @param charset the charset to use for encoding 348 * @param options options specifying how the file is opened 349 * @return a new Writer on the origin. 350 * @throws IOException if an I/O error occurs opening or creating the file. 351 * @throws UnsupportedOperationException if the origin cannot be converted to a Path. 352 */ 353 public Writer getWriter(final Charset charset, final OpenOption... options) throws IOException { 354 return Files.newBufferedWriter(getPath(), charset, options); 355 } 356 357 @Override 358 public String toString() { 359 return origin.toString(); 360 } 361}