001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.test.util; 020 021import java.io.BufferedOutputStream; 022import java.io.File; 023import java.io.FileInputStream; 024import java.io.FileOutputStream; 025import java.io.IOException; 026import java.io.OutputStream; 027import java.io.RandomAccessFile; 028import java.nio.charset.StandardCharsets; 029import java.nio.file.Files; 030import java.util.ArrayList; 031import java.util.Collection; 032import java.util.Properties; 033import java.util.UUID; 034 035/** 036 * Provides utility methods to read and write (temporary) files. 037 */ 038public class TestFileUtils { 039 040 private static final File TMP = new File( 041 System.getProperty("java.io.tmpdir"), 042 "aether-" + UUID.randomUUID().toString().substring(0, 8)); 043 044 static { 045 Runtime.getRuntime().addShutdownHook(new Thread(() -> { 046 try { 047 deleteFile(TMP); 048 } catch (IOException e) { 049 e.printStackTrace(); 050 } 051 })); 052 } 053 054 private TestFileUtils() { 055 // hide constructor 056 } 057 058 public static void deleteTempFiles() throws IOException { 059 deleteFile(TMP); 060 } 061 062 public static void deleteFile(File file) throws IOException { 063 if (file == null) { 064 return; 065 } 066 067 Collection<File> undeletables = new ArrayList<>(); 068 069 delete(file, undeletables); 070 071 if (!undeletables.isEmpty()) { 072 throw new IOException("Failed to delete " + undeletables); 073 } 074 } 075 076 private static void delete(File file, Collection<File> undeletables) { 077 String[] children = file.list(); 078 if (children != null) { 079 for (String child : children) { 080 delete(new File(file, child), undeletables); 081 } 082 } 083 084 if (!del(file)) { 085 undeletables.add(file.getAbsoluteFile()); 086 } 087 } 088 089 private static boolean del(File file) { 090 for (int i = 0; i < 10; i++) { 091 if (file.delete() || !file.exists()) { 092 return true; 093 } 094 } 095 return false; 096 } 097 098 public static boolean mkdirs(File directory) { 099 if (directory == null) { 100 return false; 101 } 102 103 if (directory.exists()) { 104 return false; 105 } 106 if (directory.mkdir()) { 107 return true; 108 } 109 110 File canonDir = null; 111 try { 112 canonDir = directory.getCanonicalFile(); 113 } catch (IOException e) { 114 return false; 115 } 116 117 File parentDir = canonDir.getParentFile(); 118 return (parentDir != null && (mkdirs(parentDir) || parentDir.exists()) && canonDir.mkdir()); 119 } 120 121 public static File createTempFile(String contents) throws IOException { 122 return createTempFile(contents.getBytes(StandardCharsets.UTF_8), 1); 123 } 124 125 public static File createTempFile(byte[] pattern, int repeat) throws IOException { 126 mkdirs(TMP); 127 File tmpFile = File.createTempFile("tmpfile-", ".data", TMP); 128 writeBytes(tmpFile, pattern, repeat); 129 return tmpFile; 130 } 131 132 /** 133 * Creates a temporary directory. 134 * 135 * @return the temporary directory 136 * @throws IOException if an I/O error occurs 137 * @deprecated use @TempDir (JUnit 5} Or TemporaryFolder (JUnit 4) instead 138 */ 139 @Deprecated 140 public static File createTempDir() throws IOException { 141 return createTempDir(""); 142 } 143 144 /** 145 * Creates a temporary directory. 146 * 147 * @return the temporary directory 148 * @throws IOException if an I/O error occurs 149 * @deprecated use {@code @TempDir) (JUnit 5} Or {@code TemporaryFolder} (JUnit 4) instead 150 */ 151 @Deprecated 152 public static File createTempDir(String suffix) throws IOException { 153 mkdirs(TMP); 154 File tmpFile = File.createTempFile("tmpdir-", suffix, TMP); 155 deleteFile(tmpFile); 156 mkdirs(tmpFile); 157 return tmpFile; 158 } 159 160 public static long copyFile(File source, File target) throws IOException { 161 long total = 0; 162 163 FileInputStream fis = null; 164 OutputStream fos = null; 165 try { 166 fis = new FileInputStream(source); 167 168 mkdirs(target.getParentFile()); 169 170 fos = new BufferedOutputStream(new FileOutputStream(target)); 171 172 for (byte[] buffer = new byte[1024 * 32]; ; ) { 173 int bytes = fis.read(buffer); 174 if (bytes < 0) { 175 break; 176 } 177 178 fos.write(buffer, 0, bytes); 179 180 total += bytes; 181 } 182 183 fos.close(); 184 fos = null; 185 186 fis.close(); 187 fis = null; 188 } finally { 189 try { 190 if (fos != null) { 191 fos.close(); 192 } 193 } catch (final IOException e) { 194 // Suppressed due to an exception already thrown in the try block. 195 } finally { 196 try { 197 if (fis != null) { 198 fis.close(); 199 } 200 } catch (final IOException e) { 201 // Suppressed due to an exception already thrown in the try block. 202 } 203 } 204 } 205 206 return total; 207 } 208 209 /** 210 * Reads the contents of a file into a byte array. 211 * 212 * @param file the file to read 213 * @return the contents of the file as a byte array 214 * @throws IOException if an I/O error occurs 215 * @deprecated use {@code Files.readAllBytes(Path)} instead 216 */ 217 @Deprecated 218 public static byte[] readBytes(File file) throws IOException { 219 RandomAccessFile in = null; 220 try { 221 in = new RandomAccessFile(file, "r"); 222 byte[] actual = new byte[(int) in.length()]; 223 in.readFully(actual); 224 in.close(); 225 in = null; 226 return actual; 227 } finally { 228 try { 229 if (in != null) { 230 in.close(); 231 } 232 } catch (final IOException e) { 233 // Suppressed due to an exception already thrown in the try block. 234 } 235 } 236 } 237 238 public static void writeBytes(File file, byte[] pattern, int repeat) throws IOException { 239 file.deleteOnExit(); 240 file.getParentFile().mkdirs(); 241 OutputStream out = null; 242 try { 243 out = new BufferedOutputStream(new FileOutputStream(file)); 244 for (int i = 0; i < repeat; i++) { 245 out.write(pattern); 246 } 247 out.close(); 248 out = null; 249 } finally { 250 try { 251 if (out != null) { 252 out.close(); 253 } 254 } catch (final IOException e) { 255 // Suppressed due to an exception already thrown in the try block. 256 } 257 } 258 } 259 260 public static String readString(File file) throws IOException { 261 byte[] content = Files.readAllBytes(file.toPath()); 262 return new String(content, StandardCharsets.UTF_8); 263 } 264 265 public static void writeString(File file, String content) throws IOException { 266 writeBytes(file, content.getBytes(StandardCharsets.UTF_8), 1); 267 } 268 269 public static void writeString(File file, String content, long timestamp) throws IOException { 270 writeBytes(file, content.getBytes(StandardCharsets.UTF_8), 1); 271 file.setLastModified(timestamp); 272 } 273 274 public static void readProps(File file, Properties props) throws IOException { 275 FileInputStream fis = null; 276 try { 277 fis = new FileInputStream(file); 278 props.load(fis); 279 fis.close(); 280 fis = null; 281 } finally { 282 try { 283 if (fis != null) { 284 fis.close(); 285 } 286 } catch (final IOException e) { 287 // Suppressed due to an exception already thrown in the try block. 288 } 289 } 290 } 291 292 public static void writeProps(File file, Properties props) throws IOException { 293 file.getParentFile().mkdirs(); 294 295 FileOutputStream fos = null; 296 try { 297 fos = new FileOutputStream(file); 298 props.store(fos, "aether-test"); 299 fos.close(); 300 fos = null; 301 } finally { 302 try { 303 if (fos != null) { 304 fos.close(); 305 } 306 } catch (final IOException e) { 307 // Suppressed due to an exception already thrown in the try block. 308 } 309 } 310 } 311}