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, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.hadoop.fs;
019    
020    import org.apache.hadoop.classification.InterfaceAudience;
021    import org.apache.hadoop.classification.InterfaceStability;
022    import org.apache.hadoop.fs.permission.FsPermission;
023    import org.apache.hadoop.util.DataChecksum;
024    import org.apache.hadoop.util.Progressable;
025    
026    /**
027     * This class contains options related to file system operations.
028     */
029    @InterfaceAudience.Public
030    @InterfaceStability.Evolving
031    public final class Options {
032      /**
033       * Class to support the varargs for create() options.
034       *
035       */
036      public static class CreateOpts {
037        private CreateOpts() { };
038        public static BlockSize blockSize(long bs) { 
039          return new BlockSize(bs);
040        }
041        public static BufferSize bufferSize(int bs) { 
042          return new BufferSize(bs);
043        }
044        public static ReplicationFactor repFac(short rf) { 
045          return new ReplicationFactor(rf);
046        }
047        public static BytesPerChecksum bytesPerChecksum(short crc) {
048          return new BytesPerChecksum(crc);
049        }
050        public static ChecksumParam checksumParam(
051            ChecksumOpt csumOpt) {
052          return new ChecksumParam(csumOpt);
053        }
054        public static Perms perms(FsPermission perm) {
055          return new Perms(perm);
056        }
057        public static CreateParent createParent() {
058          return new CreateParent(true);
059        }
060        public static CreateParent donotCreateParent() {
061          return new CreateParent(false);
062        }
063        
064        public static class BlockSize extends CreateOpts {
065          private final long blockSize;
066          protected BlockSize(long bs) {
067            if (bs <= 0) {
068              throw new IllegalArgumentException(
069                            "Block size must be greater than 0");
070            }
071            blockSize = bs; 
072          }
073          public long getValue() { return blockSize; }
074        }
075        
076        public static class ReplicationFactor extends CreateOpts {
077          private final short replication;
078          protected ReplicationFactor(short rf) { 
079            if (rf <= 0) {
080              throw new IllegalArgumentException(
081                          "Replication must be greater than 0");
082            }
083            replication = rf;
084          }
085          public short getValue() { return replication; }
086        }
087        
088        public static class BufferSize extends CreateOpts {
089          private final int bufferSize;
090          protected BufferSize(int bs) {
091            if (bs <= 0) {
092              throw new IllegalArgumentException(
093                            "Buffer size must be greater than 0");
094            }
095            bufferSize = bs; 
096          }
097          public int getValue() { return bufferSize; }
098        }
099    
100        /** This is not needed if ChecksumParam is specified. **/
101        public static class BytesPerChecksum extends CreateOpts {
102          private final int bytesPerChecksum;
103          protected BytesPerChecksum(short bpc) { 
104            if (bpc <= 0) {
105              throw new IllegalArgumentException(
106                            "Bytes per checksum must be greater than 0");
107            }
108            bytesPerChecksum = bpc; 
109          }
110          public int getValue() { return bytesPerChecksum; }
111        }
112    
113        public static class ChecksumParam extends CreateOpts {
114          private final ChecksumOpt checksumOpt;
115          protected ChecksumParam(ChecksumOpt csumOpt) {
116            checksumOpt = csumOpt;
117          }
118          public ChecksumOpt getValue() { return checksumOpt; }
119        }
120        
121        public static class Perms extends CreateOpts {
122          private final FsPermission permissions;
123          protected Perms(FsPermission perm) { 
124            if(perm == null) {
125              throw new IllegalArgumentException("Permissions must not be null");
126            }
127            permissions = perm; 
128          }
129          public FsPermission getValue() { return permissions; }
130        }
131        
132        public static class Progress extends CreateOpts {
133          private final Progressable progress;
134          protected Progress(Progressable prog) { 
135            if(prog == null) {
136              throw new IllegalArgumentException("Progress must not be null");
137            }
138            progress = prog;
139          }
140          public Progressable getValue() { return progress; }
141        }
142        
143        public static class CreateParent extends CreateOpts {
144          private final boolean createParent;
145          protected CreateParent(boolean createPar) {
146            createParent = createPar;}
147          public boolean getValue() { return createParent; }
148        }
149    
150        
151        /**
152         * Get an option of desired type
153         * @param clazz is the desired class of the opt
154         * @param opts - not null - at least one opt must be passed
155         * @return an opt from one of the opts of type theClass.
156         *   returns null if there isn't any
157         */
158        static <T extends CreateOpts> T getOpt(Class<T> clazz, CreateOpts... opts) {
159          if (opts == null) {
160            throw new IllegalArgumentException("Null opt");
161          }
162          T result = null;
163          for (int i = 0; i < opts.length; ++i) {
164            if (opts[i].getClass() == clazz) {
165              if (result != null) {
166                throw new IllegalArgumentException("multiple opts varargs: " + clazz);
167              }
168    
169              @SuppressWarnings("unchecked")
170              T t = (T)opts[i];
171              result = t;
172            }
173          }
174          return result;
175        }
176        /**
177         * set an option
178         * @param newValue  the option to be set
179         * @param opts  - the option is set into this array of opts
180         * @return updated CreateOpts[] == opts + newValue
181         */
182        static <T extends CreateOpts> CreateOpts[] setOpt(final T newValue,
183            final CreateOpts... opts) {
184          final Class<?> clazz = newValue.getClass();
185          boolean alreadyInOpts = false;
186          if (opts != null) {
187            for (int i = 0; i < opts.length; ++i) {
188              if (opts[i].getClass() == clazz) {
189                if (alreadyInOpts) {
190                  throw new IllegalArgumentException("multiple opts varargs: " + clazz);
191                }
192                alreadyInOpts = true;
193                opts[i] = newValue;
194              }
195            }
196          }
197          CreateOpts[] resultOpt = opts;
198          if (!alreadyInOpts) { // no newValue in opt
199            final int oldLength = opts == null? 0: opts.length;
200            CreateOpts[] newOpts = new CreateOpts[oldLength + 1];
201            if (oldLength > 0) {
202              System.arraycopy(opts, 0, newOpts, 0, oldLength);
203            }
204            newOpts[oldLength] = newValue;
205            resultOpt = newOpts;
206          }
207          return resultOpt;
208        }
209      }
210    
211      /**
212       * Enum to support the varargs for rename() options
213       */
214      public static enum Rename {
215        NONE((byte) 0), // No options
216        OVERWRITE((byte) 1); // Overwrite the rename destination
217    
218        private final byte code;
219        
220        private Rename(byte code) {
221          this.code = code;
222        }
223    
224        public static Rename valueOf(byte code) {
225          return code < 0 || code >= values().length ? null : values()[code];
226        }
227    
228        public byte value() {
229          return code;
230        }
231      }
232    
233      /**
234       * This is used in FileSystem and FileContext to specify checksum options.
235       */
236      public static class ChecksumOpt {
237        private final DataChecksum.Type checksumType;
238        private final int bytesPerChecksum;
239    
240        /**
241         * Create a uninitialized one
242         */
243        public ChecksumOpt() {
244          this(DataChecksum.Type.DEFAULT, -1);
245        }
246    
247        /**
248         * Normal ctor
249         * @param type checksum type
250         * @param size bytes per checksum
251         */
252        public ChecksumOpt(DataChecksum.Type type, int size) {
253          checksumType = type;
254          bytesPerChecksum = size;
255        }
256    
257        public int getBytesPerChecksum() {
258          return bytesPerChecksum;
259        }
260    
261        public DataChecksum.Type getChecksumType() {
262          return checksumType;
263        }
264        
265        @Override
266        public String toString() {
267          return checksumType + ":" + bytesPerChecksum;
268        }
269    
270        /**
271         * Create a ChecksumOpts that disables checksum
272         */
273        public static ChecksumOpt createDisabled() {
274          return new ChecksumOpt(DataChecksum.Type.NULL, -1);
275        }
276    
277        /**
278         * A helper method for processing user input and default value to 
279         * create a combined checksum option. This is a bit complicated because
280         * bytesPerChecksum is kept for backward compatibility.
281         *
282         * @param defaultOpt Default checksum option
283         * @param userOpt User-specified checksum option. Ignored if null.
284         * @param userBytesPerChecksum User-specified bytesPerChecksum
285         *                Ignored if < 0.
286         */
287        public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt, 
288            ChecksumOpt userOpt, int userBytesPerChecksum) {
289          final boolean useDefaultType;
290          final DataChecksum.Type type;
291          if (userOpt != null 
292              && userOpt.getChecksumType() != DataChecksum.Type.DEFAULT) {
293            useDefaultType = false;
294            type = userOpt.getChecksumType();
295          } else {
296            useDefaultType = true;
297            type = defaultOpt.getChecksumType();
298          }
299    
300          //  bytesPerChecksum - order of preference
301          //    user specified value in bytesPerChecksum
302          //    user specified value in checksumOpt
303          //    default.
304          if (userBytesPerChecksum > 0) {
305            return new ChecksumOpt(type, userBytesPerChecksum);
306          } else if (userOpt != null && userOpt.getBytesPerChecksum() > 0) {
307            return !useDefaultType? userOpt
308                : new ChecksumOpt(type, userOpt.getBytesPerChecksum());
309          } else {
310            return useDefaultType? defaultOpt
311                : new ChecksumOpt(type, defaultOpt.getBytesPerChecksum());
312          }
313        }
314    
315        /**
316         * A helper method for processing user input and default value to 
317         * create a combined checksum option. 
318         *
319         * @param defaultOpt Default checksum option
320         * @param userOpt User-specified checksum option
321         */
322        public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt,
323            ChecksumOpt userOpt) {
324          return processChecksumOpt(defaultOpt, userOpt, -1);
325        }
326      }
327    }