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;
025import org.apache.hadoop.HadoopIllegalArgumentException;
026
027/**
028 * This class contains options related to file system operations.
029 */
030@InterfaceAudience.Public
031@InterfaceStability.Evolving
032public 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}