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.spi.io; 020 021import java.io.Closeable; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.UncheckedIOException; 025import java.nio.ByteBuffer; 026import java.nio.file.Files; 027import java.nio.file.NoSuchFileException; 028import java.nio.file.Path; 029 030/** 031 * A utility component to perform file-based operations. 032 * 033 * @since 2.0.0 034 */ 035public interface PathProcessor { 036 /** 037 * Returns last modified of path in milliseconds, if exists. 038 * 039 * @param path The path, may be {@code null}. 040 * @throws UncheckedIOException If an I/O error occurs. 041 */ 042 default long lastModified(Path path, long defValue) { 043 try { 044 return Files.getLastModifiedTime(path).toMillis(); 045 } catch (NoSuchFileException e) { 046 return defValue; 047 } catch (IOException e) { 048 throw new UncheckedIOException(e); 049 } 050 } 051 052 /** 053 * Sets last modified of path in milliseconds, if exists. 054 * 055 * @param path The path, may be {@code null}. 056 * @throws IOException If an I/O error occurs. Some exceptions/reasons of failure to set mtime may be swallowed, 057 * and can be multiple, ranging from "file not found" to cases when FS does not support the setting the mtime. 058 * @since 2.0.0 059 */ 060 boolean setLastModified(Path path, long value) throws IOException; 061 062 /** 063 * Returns size of file, if exists. 064 * 065 * @param path The path, may be {@code null}. 066 * @throws UncheckedIOException If an I/O error occurs. 067 */ 068 default long size(Path path, long defValue) { 069 try { 070 return Files.size(path); 071 } catch (NoSuchFileException e) { 072 return defValue; 073 } catch (IOException e) { 074 throw new UncheckedIOException(e); 075 } 076 } 077 078 /** 079 * Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for 080 * the target file. In case of an error, the created directories will be left on the file system. 081 * 082 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 083 * @param data The data to write, may be {@code null}. 084 * @throws IOException If an I/O error occurs. 085 */ 086 void write(Path target, String data) throws IOException; 087 088 /** 089 * Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, 090 * the created directories will be left on the file system. 091 * 092 * @param target The file to write to, must not be {@code null}. This file will be overwritten. 093 * @param source The stream to write to the file, must not be {@code null}. 094 * @throws IOException If an I/O error occurs. 095 */ 096 void write(Path target, InputStream source) throws IOException; 097 098 /** 099 * 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}