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 */
018package org.apache.hadoop.fs;
019
020import org.apache.hadoop.classification.InterfaceAudience;
021import org.apache.hadoop.classification.InterfaceStability;
022import org.apache.hadoop.fs.permission.FsPermission;
023import org.apache.hadoop.util.DataChecksum;
024import org.apache.hadoop.util.Progressable;
025
026/**
027 * This class contains options related to file system operations.
028 */
029@InterfaceAudience.Public
030@InterfaceStability.Evolving
031public 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}