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 theClass 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        protected static CreateOpts getOpt(Class<? extends CreateOpts> theClass,  CreateOpts ...opts) {
159          if (opts == null) {
160            throw new IllegalArgumentException("Null opt");
161          }
162          CreateOpts result = null;
163          for (int i = 0; i < opts.length; ++i) {
164            if (opts[i].getClass() == theClass) {
165              if (result != null) 
166                throw new IllegalArgumentException("multiple blocksize varargs");
167              result = opts[i];
168            }
169          }
170          return result;
171        }
172        /**
173         * set an option
174         * @param newValue  the option to be set
175         * @param opts  - the option is set into this array of opts
176         * @return updated CreateOpts[] == opts + newValue
177         */
178        protected static <T extends CreateOpts> CreateOpts[] setOpt(T newValue,
179            CreateOpts ...opts) {
180          boolean alreadyInOpts = false;
181          if (opts != null) {
182            for (int i = 0; i < opts.length; ++i) {
183              if (opts[i].getClass() == newValue.getClass()) {
184                if (alreadyInOpts) 
185                  throw new IllegalArgumentException("multiple opts varargs");
186                alreadyInOpts = true;
187                opts[i] = newValue;
188              }
189            }
190          }
191          CreateOpts[] resultOpt = opts;
192          if (!alreadyInOpts) { // no newValue in opt
193            CreateOpts[] newOpts = new CreateOpts[opts.length + 1];
194            System.arraycopy(opts, 0, newOpts, 0, opts.length);
195            newOpts[opts.length] = newValue;
196            resultOpt = newOpts;
197          }
198          return resultOpt;
199        }
200      }
201    
202      /**
203       * Enum to support the varargs for rename() options
204       */
205      public static enum Rename {
206        NONE((byte) 0), // No options
207        OVERWRITE((byte) 1); // Overwrite the rename destination
208    
209        private final byte code;
210        
211        private Rename(byte code) {
212          this.code = code;
213        }
214    
215        public static Rename valueOf(byte code) {
216          return code < 0 || code >= values().length ? null : values()[code];
217        }
218    
219        public byte value() {
220          return code;
221        }
222      }
223    
224      /**
225       * This is used in FileSystem and FileContext to specify checksum options.
226       */
227      public static class ChecksumOpt {
228        private final int crcBlockSize;
229        private final DataChecksum.Type crcType;
230    
231        /**
232         * Create a uninitialized one
233         */
234        public ChecksumOpt() {
235          crcBlockSize = -1;
236          crcType = DataChecksum.Type.DEFAULT;
237        }
238    
239        /**
240         * Normal ctor
241         * @param type checksum type
242         * @param size bytes per checksum
243         */
244        public ChecksumOpt(DataChecksum.Type type, int size) {
245          crcBlockSize = size;
246          crcType = type;
247        }
248    
249        public int getBytesPerChecksum() {
250          return crcBlockSize;
251        }
252    
253        public DataChecksum.Type getChecksumType() {
254          return crcType;
255        }
256    
257        /**
258         * Create a ChecksumOpts that disables checksum
259         */
260        public static ChecksumOpt createDisabled() {
261          return new ChecksumOpt(DataChecksum.Type.NULL, -1);
262        }
263    
264        /**
265         * A helper method for processing user input and default value to 
266         * create a combined checksum option. This is a bit complicated because
267         * bytesPerChecksum is kept for backward compatibility.
268         *
269         * @param defaultOpt Default checksum option
270         * @param userOpt User-specified checksum option. Ignored if null.
271         * @param userBytesPerChecksum User-specified bytesPerChecksum
272         *                Ignored if < 0.
273         */
274        public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt, 
275            ChecksumOpt userOpt, int userBytesPerChecksum) {
276          // The following is done to avoid unnecessary creation of new objects.
277          // tri-state variable: 0 default, 1 userBytesPerChecksum, 2 userOpt
278          short whichSize;
279          // true default, false userOpt
280          boolean useDefaultType;
281          
282          //  bytesPerChecksum - order of preference
283          //    user specified value in bytesPerChecksum
284          //    user specified value in checksumOpt
285          //    default.
286          if (userBytesPerChecksum > 0) {
287            whichSize = 1; // userBytesPerChecksum
288          } else if (userOpt != null && userOpt.getBytesPerChecksum() > 0) {
289            whichSize = 2; // userOpt
290          } else {
291            whichSize = 0; // default
292          }
293    
294          // checksum type - order of preference
295          //   user specified value in checksumOpt
296          //   default.
297          if (userOpt != null &&
298                userOpt.getChecksumType() != DataChecksum.Type.DEFAULT) {
299            useDefaultType = false;
300          } else {
301            useDefaultType = true;
302          }
303    
304          // Short out the common and easy cases
305          if (whichSize == 0 && useDefaultType) {
306            return defaultOpt;
307          } else if (whichSize == 2 && !useDefaultType) {
308            return userOpt;
309          }
310    
311          // Take care of the rest of combinations
312          DataChecksum.Type type = useDefaultType ? defaultOpt.getChecksumType() :
313              userOpt.getChecksumType();
314          if (whichSize == 0) {
315            return new ChecksumOpt(type, defaultOpt.getBytesPerChecksum());
316          } else if (whichSize == 1) {
317            return new ChecksumOpt(type, userBytesPerChecksum);
318          } else {
319            return new ChecksumOpt(type, userOpt.getBytesPerChecksum());
320          }
321        }
322    
323        /**
324         * A helper method for processing user input and default value to 
325         * create a combined checksum option. 
326         *
327         * @param defaultOpt Default checksum option
328         * @param userOpt User-specified checksum option
329         */
330        public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt,
331            ChecksumOpt userOpt) {
332          return processChecksumOpt(defaultOpt, userOpt, -1);
333        }
334      }
335    }