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 }