View Javadoc
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 }