1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.eclipse.aether.spi.io; 20 21 import java.io.Closeable; 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.UncheckedIOException; 25 import java.nio.ByteBuffer; 26 import java.nio.file.Files; 27 import java.nio.file.NoSuchFileException; 28 import java.nio.file.Path; 29 30 /** 31 * A utility component to perform file-based operations. 32 * 33 * @since 2.0.0 34 */ 35 public interface PathProcessor { 36 /** 37 * Returns last modified of path in milliseconds, if exists. 38 * 39 * @param path The path, may be {@code null}. 40 * @throws UncheckedIOException If an I/O error occurs. 41 */ 42 default long lastModified(Path path, long defValue) { 43 try { 44 return Files.getLastModifiedTime(path).toMillis(); 45 } catch (NoSuchFileException e) { 46 return defValue; 47 } catch (IOException e) { 48 throw new UncheckedIOException(e); 49 } 50 } 51 52 /** 53 * Sets last modified of path in milliseconds, if exists. 54 * 55 * @param path The path, may be {@code null}. 56 * @throws IOException If an I/O error occurs. Some exceptions/reasons of failure to set mtime may be swallowed, 57 * and can be multiple, ranging from "file not found" to cases when FS does not support the setting the mtime. 58 * @since 2.0.0 59 */ 60 boolean setLastModified(Path path, long value) throws IOException; 61 62 /** 63 * Returns size of file, if exists. 64 * 65 * @param path The path, may be {@code null}. 66 * @throws UncheckedIOException If an I/O error occurs. 67 */ 68 default long size(Path path, long defValue) { 69 try { 70 return Files.size(path); 71 } catch (NoSuchFileException e) { 72 return defValue; 73 } catch (IOException e) { 74 throw new UncheckedIOException(e); 75 } 76 } 77 78 /** 79 * Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for 80 * the target file. In case of an error, the created directories will be left on the file system. 81 * 82 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 83 * @param data The data to write, may be {@code null}. 84 * @throws IOException If an I/O error occurs. 85 */ 86 void write(Path target, String data) throws IOException; 87 88 /** 89 * Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, 90 * the created directories will be left on the file system. 91 * 92 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 93 * @param source The stream to write to the file, must not be {@code null}. 94 * @throws IOException If an I/O error occurs. 95 */ 96 void write(Path target, InputStream source) throws IOException; 97 98 /** 99 * Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for 100 * the target file. In case of an error, the created directories will be left on the file system. 101 * 102 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 103 * @param data The data to write, may be {@code null}. 104 * @throws IOException If an I/O error occurs. 105 * @since 2.0.13 106 */ 107 void writeWithBackup(Path target, String data) throws IOException; 108 109 /** 110 * Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, 111 * the created directories will be left on the file system. 112 * 113 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 114 * @param source The stream to write to the file, must not be {@code null}. 115 * @throws IOException If an I/O error occurs. 116 * @since 2.0.13 117 */ 118 void writeWithBackup(Path target, InputStream source) throws IOException; 119 120 /** 121 * Moves the specified source file to the given target file. If the target file already exists, it is overwritten. 122 * Creates the necessary directories for the target file. In case of an error, the created directories will be left 123 * on the file system. 124 * 125 * @param source The file to move from, must not be {@code null}. 126 * @param target The file to move to, must not be {@code null}. 127 * @throws IOException If an I/O error occurs. 128 */ 129 void move(Path source, Path target) throws IOException; 130 131 /** 132 * Copies the specified source file to the given target file. Creates the necessary directories for the target file. 133 * In case of an error, the created directories will be left on the file system. 134 * 135 * @param source The file to copy from, must not be {@code null}. 136 * @param target The file to copy to, must not be {@code null}. 137 * @throws IOException If an I/O error occurs. 138 */ 139 default void copy(Path source, Path target) throws IOException { 140 copy(source, target, null); 141 } 142 143 /** 144 * Same as {@link #copy(Path, Path)} but sets source file last modified timestamp on target as well. 145 * 146 * @param source The file to copy from, must not be {@code null}. 147 * @param target The file to copy to, must not be {@code null}. 148 * @throws IOException If an I/O error occurs. 149 * @see #setLastModified(Path, long) 150 * @since 2.0.0 151 */ 152 default void copyWithTimestamp(Path source, Path target) throws IOException { 153 copy(source, target, null); 154 setLastModified(target, Files.getLastModifiedTime(source).toMillis()); 155 } 156 157 /** 158 * Copies the specified source file to the given target file. Creates the necessary directories for the target file. 159 * In case of an error, the created directories will be left on the file system. 160 * 161 * @param source The file to copy from, must not be {@code null}. 162 * @param target The file to copy to, must not be {@code null}. 163 * @param listener The listener to notify about the copy progress, may be {@code null}. 164 * @return The number of copied bytes. 165 * @throws IOException If an I/O error occurs. 166 */ 167 long copy(Path source, Path target, ProgressListener listener) throws IOException; 168 169 /** 170 * A listener object that is notified for every progress made while copying files. 171 * 172 * @see PathProcessor#copy(Path, Path, ProgressListener) 173 */ 174 interface ProgressListener { 175 void progressed(ByteBuffer buffer) throws IOException; 176 } 177 178 // Temporary files 179 180 /** 181 * A temporary file, that is removed when closed. 182 * 183 * @since 2.0.13 184 */ 185 interface TempFile extends Closeable { 186 /** 187 * Returns the path of the created temp file. 188 */ 189 Path getPath(); 190 } 191 192 /** 193 * A collocated temporary file, that resides next to a "target" file, and is removed when closed. 194 * 195 * @since 2.0.13 196 */ 197 interface CollocatedTempFile extends TempFile { 198 /** 199 * Upon close, atomically moves temp file to target file it is collocated with overwriting target (if exists). 200 * Invocation of this method merely signals that caller ultimately wants temp file to replace the target 201 * file, but when this method returns, the move operation did not yet happen, it will happen when this 202 * instance is closed. 203 * <p> 204 * Invoking this method <em>without writing to temp file</em> {@link #getPath()} (thus, not creating a temp 205 * file to be moved) is considered a bug, a mistake of the caller. Caller of this method should ensure 206 * that this method is invoked ONLY when the temp file is created and moving it to its final place is 207 * required. 208 */ 209 void move() throws IOException; 210 } 211 212 /** 213 * Creates a {@link TempFile} instance and backing temporary file on file system. It will be located in the default 214 * temporary-file directory. Returned instance should be handled in try-with-resource construct and created 215 * temp file is removed (if exists) when returned instance is closed. 216 * <p> 217 * This method uses {@link Files#createTempFile(String, String, java.nio.file.attribute.FileAttribute[])} to create 218 * the temporary file on file system. 219 * 220 * @since 2.0.13 221 */ 222 TempFile newTempFile() throws IOException; 223 224 /** 225 * Creates a {@link CollocatedTempFile} instance for given file without backing file. The path will be located in 226 * same directory where given file is, and will reuse its name for generated (randomized) name. Returned instance 227 * should be handled in try-with-resource and created temp path is removed (if exists) when returned instance is 228 * closed. The {@link CollocatedTempFile#move()} makes possible to atomically replace passed in file with the 229 * processed content written into a file backing the {@link CollocatedTempFile} instance. 230 * <p> 231 * The {@code file} nor it's parent directories have to exist. The parent directories are created if needed. 232 * <p> 233 * This method uses {@link Path#resolve(String)} to create the temporary file path in passed in file parent 234 * directory, but it does NOT create backing file on file system. 235 * 236 * @since 2.0.13 237 */ 238 CollocatedTempFile newTempFile(Path file) throws IOException; 239 }