1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.io;
19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24 import java.nio.file.OpenOption;
25 import java.nio.file.Path;
26 import java.nio.file.StandardOpenOption;
27 import java.util.Objects;
28
29 import org.apache.commons.io.function.IOConsumer;
30 import org.apache.commons.io.function.IOFunction;
31
32 /**
33 * Enumerates access modes for {@link RandomAccessFile} with factory methods.
34 *
35 * @see RandomAccessFile#RandomAccessFile(File, String)
36 * @see RandomAccessFile#RandomAccessFile(String, String)
37 * @see Enum
38 * @since 2.12.0
39 */
40 public enum RandomAccessFileMode {
41
42 /**
43 * Defines mode {@value #R} to open a {@link RandomAccessFile} for reading only.
44 *
45 * @see RandomAccessFile#RandomAccessFile(File, String)
46 * @see RandomAccessFile#RandomAccessFile(String, String)
47 */
48 READ_ONLY(RandomAccessFileMode.R, 1), // NOPMD bug https://github.com/pmd/pmd/issues/5263
49
50 /**
51 * Defines mode {@value #RW} to open a {@link RandomAccessFile} for reading and writing.
52 *
53 * @see RandomAccessFile#RandomAccessFile(File, String)
54 * @see RandomAccessFile#RandomAccessFile(String, String)
55 */
56 READ_WRITE(RandomAccessFileMode.RW, 2), // NOPMD bug https://github.com/pmd/pmd/issues/5263
57
58 /**
59 * Defines mode {@value #RWS} to open a {@link RandomAccessFile} for reading and writing, as with {@value #RW}, and also require that every update to the
60 * file's content or metadata be written synchronously to the underlying storage device.
61 *
62 * @see RandomAccessFile#RandomAccessFile(File, String)
63 * @see RandomAccessFile#RandomAccessFile(String, String)
64 * @see StandardOpenOption#SYNC
65 */
66 READ_WRITE_SYNC_ALL(RandomAccessFileMode.RWS, 4), // NOPMD bug https://github.com/pmd/pmd/issues/5263
67
68 /**
69 * Defines mode {@value #RWD} to open a {@link RandomAccessFile} for reading and writing, as with {@value #RW}, and also require that every update to the
70 * file's content be written synchronously to the underlying storage device.
71 *
72 * @see RandomAccessFile#RandomAccessFile(File, String)
73 * @see RandomAccessFile#RandomAccessFile(String, String)
74 * @see StandardOpenOption#DSYNC
75 */
76 READ_WRITE_SYNC_CONTENT(RandomAccessFileMode.RWD, 3); // NOPMD bug https://github.com/pmd/pmd/issues/5263
77
78 private static final String R = "r";
79 private static final String RW = "rw";
80 private static final String RWD = "rwd";
81 private static final String RWS = "rws";
82
83 /**
84 * Gets the enum value that best fits the given {@link OpenOption}s.
85 * <p>
86 * The input must be a legal and working combination for NIO.
87 * </p>
88 *
89 * @param openOption options like {@link StandardOpenOption}.
90 * @return best fit, by default {@link #READ_ONLY}.
91 * @see StandardOpenOption
92 * @since 2.18.0
93 */
94 public static RandomAccessFileMode valueOf(final OpenOption... openOption) {
95 RandomAccessFileMode bestFit = READ_ONLY;
96 for (final OpenOption option : openOption) {
97 if (option instanceof StandardOpenOption) {
98 switch ((StandardOpenOption) option) {
99 case WRITE:
100 if (!bestFit.implies(READ_WRITE)) {
101 bestFit = READ_WRITE;
102 }
103 break;
104 case DSYNC:
105 if (!bestFit.implies(READ_WRITE_SYNC_CONTENT)) {
106 bestFit = READ_WRITE_SYNC_CONTENT;
107 }
108 break;
109 case SYNC:
110 if (!bestFit.implies(READ_WRITE_SYNC_ALL)) {
111 bestFit = READ_WRITE_SYNC_ALL;
112 }
113 break;
114 default:
115 // explicit case skip (spotbugs)
116 continue;
117 }
118 }
119 }
120 return bestFit;
121 }
122
123 /**
124 * Gets the {@link RandomAccessFileMode} value for the given mode, one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}.
125 *
126 * @param mode one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}.
127 * @return A RandomAccessFileMode.
128 * @throws IllegalArgumentException Thrown when mode is not one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}.
129 * @since 2.18.0
130 */
131 public static RandomAccessFileMode valueOfMode(final String mode) {
132 switch (mode) {
133 case R:
134 return READ_ONLY;
135 case RW:
136 return READ_WRITE;
137 case RWD:
138 return READ_WRITE_SYNC_CONTENT;
139 case RWS:
140 return READ_WRITE_SYNC_ALL;
141 }
142 throw new IllegalArgumentException(mode);
143 }
144
145 private final int level;
146
147 private final String mode;
148
149 RandomAccessFileMode(final String mode, final int level) {
150 this.mode = mode;
151 this.level = level;
152 }
153
154 /**
155 * Performs an operation on the {@link RandomAccessFile} specified at the given {@link Path}.
156 * <p>
157 * This method allocates and releases the {@link RandomAccessFile} given to the consumer.
158 * </p>
159 *
160 * @param file the file specifying the {@link RandomAccessFile} to open.
161 * @param consumer the function to apply.
162 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
163 * @throws IOException Thrown by the given function.
164 * @since 2.18.0
165 */
166 public void accept(final Path file, final IOConsumer<RandomAccessFile> consumer) throws IOException {
167 try (RandomAccessFile raf = create(file)) {
168 consumer.accept(raf);
169 }
170 }
171
172 /**
173 * Applies the given function for a {@link RandomAccessFile} specified at the given {@link Path}.
174 * <p>
175 * This method allocates and releases the {@link RandomAccessFile} given to the function.
176 * </p>
177 *
178 * @param <T> the return type of the function.
179 * @param file the file specifying the {@link RandomAccessFile} to open.
180 * @param function the function to apply.
181 * @return the function's result value.
182 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
183 * @throws IOException Thrown by the given function.
184 * @since 2.18.0
185 */
186 public <T> T apply(final Path file, final IOFunction<RandomAccessFile, T> function) throws IOException {
187 try (RandomAccessFile raf = create(file)) {
188 return function.apply(raf);
189 }
190 }
191
192 /**
193 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument.
194 * <p>
195 * Prefer {@link #create(Path)} over this.
196 * </p>
197 *
198 * @param file the file object
199 * @return a random access file
200 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
201 */
202 public RandomAccessFile create(final File file) throws FileNotFoundException {
203 return new IORandomAccessFile(file, mode);
204 }
205
206 /**
207 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument.
208 *
209 * @param file the file object
210 * @return a random access file
211 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
212 */
213 public RandomAccessFile create(final Path file) throws FileNotFoundException {
214 return create(Objects.requireNonNull(file.toFile(), "file"));
215 }
216
217 /**
218 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument.
219 * <p>
220 * Prefer {@link #create(Path)} over this.
221 * </p>
222 *
223 * @param name the file object
224 * @return a random access file
225 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
226 */
227 public RandomAccessFile create(final String name) throws FileNotFoundException {
228 return new IORandomAccessFile(name, mode);
229 }
230
231 /**
232 * A level for relative comparison of access mode rights, the larger, the more access.
233 * <p>
234 * The relative order from lowest to highest access rights is:
235 * </p>
236 * <ol>
237 * <li>{@link #READ_ONLY}</li>
238 * <li>{@link #READ_WRITE}</li>
239 * <li>{@link #READ_WRITE_SYNC_CONTENT}</li>
240 * <li>{@link #READ_WRITE_SYNC_ALL}</li>
241 * </ol>
242 * <p>
243 * This is unrelated to {@link #ordinal()}.
244 * </p>
245 *
246 * @return A level for relative comparison.
247 */
248 private int getLevel() {
249 return level;
250 }
251
252 /**
253 * Gets the access mode, one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}.
254 *
255 * @return one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}.
256 * @since 2.18.0
257 */
258 public String getMode() {
259 return mode;
260 }
261
262 /**
263 * Tests whether this mode implies the given {@code other} mode.
264 * <p>
265 * For example:
266 * </p>
267 * <ol>
268 * <li>{@link RandomAccessFileMode#READ_WRITE_SYNC_ALL} implies {{@link RandomAccessFileMode#READ_WRITE_SYNC_CONTENT}}.</li>
269 * <li>{@link RandomAccessFileMode#READ_WRITE_SYNC_CONTENT} implies {{@link RandomAccessFileMode#READ_WRITE}}.</li>
270 * <li>{@link RandomAccessFileMode#READ_WRITE} implies {{@link RandomAccessFileMode#READ_ONLY}}.</li>
271 * </ol>
272 *
273 * @param other the non-null mode to test against.
274 * @return whether this mode implies the given {@code other} mode.
275 * @since 2.18.0
276 */
277 public boolean implies(final RandomAccessFileMode other) {
278 // Note: The method name "implies" is inspired by java.security.Permission.implies(Permission)
279 return getLevel() >= other.getLevel();
280 }
281
282 /**
283 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument.
284 *
285 * @param name the file object
286 * @return a random access file
287 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}.
288 * @since 2.18.0
289 */
290 public IORandomAccessFile io(final String name) throws FileNotFoundException {
291 return new IORandomAccessFile(name, mode);
292 }
293
294 }