001/* 002 * Copyright 2023 the original author or authors. 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.tools.io; 017 018import static de.cuioss.tools.base.Preconditions.checkArgument; 019import static de.cuioss.tools.string.MoreStrings.isEmpty; 020import static java.util.Objects.requireNonNull; 021 022import java.io.BufferedInputStream; 023import java.io.IOException; 024import java.io.StringWriter; 025import java.nio.charset.Charset; 026import java.nio.charset.StandardCharsets; 027import java.nio.file.Files; 028import java.nio.file.Path; 029import java.nio.file.StandardCopyOption; 030 031import lombok.AccessLevel; 032import lombok.NoArgsConstructor; 033 034/** 035 * Utility class for dealing with generic / classpath related file access. 036 * 037 * @author Oliver Wolff 038 */ 039@NoArgsConstructor(access = AccessLevel.PRIVATE) 040public final class FileLoaderUtility { 041 042 /** 043 * Returns an implementation of {@link FileLoader} matching to the given path. 044 * 045 * @param pathName must not be null or empty. 046 * @return a configured implementation of {@link FileLoader}. In case the 047 * pathName is prefixed with {@link FileTypePrefix#CLASSPATH} it returns 048 * a {@link ClassPathLoader}. If prefixed with 049 * {@link FileTypePrefix#URL} it returns a {@link UrlLoader}. Otherwise, 050 * it returns a {@link FileSystemLoader}. 051 */ 052 public static FileLoader getLoaderForPath(final String pathName) { 053 if (isEmpty(pathName)) { 054 throw new IllegalArgumentException("pathName must not be null nor empty"); 055 } 056 if (pathName.startsWith(FileTypePrefix.CLASSPATH.getPrefix())) { 057 return new ClassPathLoader(pathName); 058 } 059 if (pathName.startsWith(FileTypePrefix.URL.getPrefix())) { 060 return new UrlLoader(pathName); 061 } 062 return new FileSystemLoader(pathName); 063 } 064 065 /** 066 * Helper class that copies the content of a {@link FileLoader} to the 067 * temp-folder and references it 068 * <h2>Caution: Security-Impact</h2> Creating a temp-file might introduce a 069 * security issue. Never ever use this location for sensitive information that 070 * might be of interest for an attacker 071 * 072 * @param source must not be null and represent an accessible file, 073 * saying {@link FileLoader#isReadable()} 074 * @param markDeleteOnExit if <code>true</code> the file will be marked to 075 * delete on Exit. 076 * @return a reference on a file copied in the temp folder 077 * @throws IOException 078 */ 079 @SuppressWarnings("java:S5443") // owolff: See hint Caution: Security-Impact 080 public static Path copyFileToTemp(final FileLoader source, final boolean markDeleteOnExit) throws IOException { 081 checkArgument(null != source, "Attribute with name source must not be null"); 082 checkArgument(source.isReadable(), "Source must be readable"); 083 084 final var target = Files.createTempFile(source.getFileName().getNamePart(), source.getFileName().getSuffix()); 085 086 try (final var inputStream = source.inputStream()) { 087 Files.copy(new BufferedInputStream(inputStream), target, StandardCopyOption.REPLACE_EXISTING); 088 } 089 if (markDeleteOnExit) { 090 target.toFile().deleteOnExit(); 091 } 092 return target; 093 } 094 095 /** 096 * Convenience method for reading the content from a given {@link FileLoader} 097 * into a String 098 * 099 * @param fileLoader must not be null 100 * @param charset must not be null 101 * @return The String content of the File represented by the given 102 * {@link FileLoader} 103 * @throws IOException 104 */ 105 public static String toString(final FileLoader fileLoader, final Charset charset) throws IOException { 106 requireNonNull(fileLoader); 107 final var writer = new StringWriter(); 108 try (final var inputStream = fileLoader.inputStream()) { 109 IOStreams.copy(inputStream, writer, charset); 110 } 111 return writer.toString(); 112 } 113 114 /** 115 * Convenience method for reading the content from a given {@link FileLoader} 116 * into a String read as UTF-8 String 117 * 118 * @param fileLoader must not be null 119 * @return The String content of the File represented by the given 120 * {@link FileLoader} 121 * @throws IOException 122 */ 123 public static String toString(final FileLoader fileLoader) throws IOException { 124 return toString(fileLoader, StandardCharsets.UTF_8); 125 } 126 127 /** 128 * Convenience method for reading the content from a given {@link FileLoader} 129 * into a String read as UTF-8 String 130 * 131 * @param fileLoader must not be null 132 * @return The String content of the File represented by the given 133 * {@link FileLoader} 134 * @throws IllegalArgumentException masking the actual {@link IOException} 135 * @throws NullPointerException if <code>fileLoader</code> is null 136 */ 137 public static String toStringUnchecked(final FileLoader fileLoader) { 138 requireNonNull(fileLoader); 139 try { 140 return toString(fileLoader); 141 } catch (final IOException | IllegalStateException e) { 142 throw new IllegalArgumentException("Unable to read from Path " + fileLoader.getFileName(), e); 143 } 144 } 145}