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