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