View Javadoc
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    *      http://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 }