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 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    TO_TRASH ((byte) 2); // Rename to trash
218
219    private final byte code;
220    
221    private Rename(byte code) {
222      this.code = code;
223    }
224
225    public static Rename valueOf(byte code) {
226      return code < 0 || code >= values().length ? null : values()[code];
227    }
228
229    public byte value() {
230      return code;
231    }
232  }
233
234  /**
235   * This is used in FileSystem and FileContext to specify checksum options.
236   */
237  public static class ChecksumOpt {
238    private final DataChecksum.Type checksumType;
239    private final int bytesPerChecksum;
240
241    /**
242     * Create a uninitialized one
243     */
244    public ChecksumOpt() {
245      this(DataChecksum.Type.DEFAULT, -1);
246    }
247
248    /**
249     * Normal ctor
250     * @param type checksum type
251     * @param size bytes per checksum
252     */
253    public ChecksumOpt(DataChecksum.Type type, int size) {
254      checksumType = type;
255      bytesPerChecksum = size;
256    }
257
258    public int getBytesPerChecksum() {
259      return bytesPerChecksum;
260    }
261
262    public DataChecksum.Type getChecksumType() {
263      return checksumType;
264    }
265    
266    @Override
267    public String toString() {
268      return checksumType + ":" + bytesPerChecksum;
269    }
270
271    /**
272     * Create a ChecksumOpts that disables checksum
273     */
274    public static ChecksumOpt createDisabled() {
275      return new ChecksumOpt(DataChecksum.Type.NULL, -1);
276    }
277
278    /**
279     * A helper method for processing user input and default value to 
280     * create a combined checksum option. This is a bit complicated because
281     * bytesPerChecksum is kept for backward compatibility.
282     *
283     * @param defaultOpt Default checksum option
284     * @param userOpt User-specified checksum option. Ignored if null.
285     * @param userBytesPerChecksum User-specified bytesPerChecksum
286     *                Ignored if < 0.
287     */
288    public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt, 
289        ChecksumOpt userOpt, int userBytesPerChecksum) {
290      final boolean useDefaultType;
291      final DataChecksum.Type type;
292      if (userOpt != null 
293          && userOpt.getChecksumType() != DataChecksum.Type.DEFAULT) {
294        useDefaultType = false;
295        type = userOpt.getChecksumType();
296      } else {
297        useDefaultType = true;
298        type = defaultOpt.getChecksumType();
299      }
300
301      //  bytesPerChecksum - order of preference
302      //    user specified value in bytesPerChecksum
303      //    user specified value in checksumOpt
304      //    default.
305      if (userBytesPerChecksum > 0) {
306        return new ChecksumOpt(type, userBytesPerChecksum);
307      } else if (userOpt != null && userOpt.getBytesPerChecksum() > 0) {
308        return !useDefaultType? userOpt
309            : new ChecksumOpt(type, userOpt.getBytesPerChecksum());
310      } else {
311        return useDefaultType? defaultOpt
312            : new ChecksumOpt(type, defaultOpt.getBytesPerChecksum());
313      }
314    }
315
316    /**
317     * A helper method for processing user input and default value to 
318     * create a combined checksum option. 
319     *
320     * @param defaultOpt Default checksum option
321     * @param userOpt User-specified checksum option
322     */
323    public static ChecksumOpt processChecksumOpt(ChecksumOpt defaultOpt,
324        ChecksumOpt userOpt) {
325      return processChecksumOpt(defaultOpt, userOpt, -1);
326    }
327  }
328}