content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  package com.aliyun.odps.volume;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.util.ArrayList;
  
  /**
   * VolumeFileSystem have volume partition dir as root, so all paths are
   * relative to partition dir.
   * <p>Only available at job runtime.
   */
  public abstract class FileSystem {
  
    /**
     * Opens an FSDataInputStream at the indicated Path.
     *
     * @param f
     *     the file name to open
     * @param bufferSize
     *     the size of the buffer to be used.
     */
    public abstract FSDataInputStream open(Path f, int bufferSize)
        throws IOException;
  
    /**
     * Opens an FSDataInputStream at the indicated Path.
     *
     * @param f
     *     the file to open
     */
    public abstract FSDataInputStream open(Path f) throws IOException;
  
    /**
     * Create an FSDataOutputStream at the indicated Path.
     * Files are overwritten by default.
     *
     * @param f
     *     the file to create
     */
    public FSDataOutputStream create(Path f) throws IOException {
      return create(f, true);
    }
  
    /**
     * Create an FSDataOutputStream at the indicated Path.
     *
     * @param f
     *     the file to create
     * @param overwrite
     *     if a file with this name already exists, then if true,
     *     the file will be overwritten, and if false an exception will be thrown.
     */
    public abstract FSDataOutputStream create(Path f, boolean overwrite)
        throws IOException;
  
    /**
     * Create an FSDataOutputStream at the indicated Path.
     *
     * @param f
     *     the file name to create
     * @param overwrite
     *     if a file with this name already exists, then if true,
     *     the file will be overwritten, and if false an error will be thrown.
     * @param bufferSize
     *     the size of the buffer to be used.
     */
    public abstract FSDataOutputStream create(Path f,
                                              boolean overwrite,
                                              int bufferSize
    ) throws IOException;
  
    /**
     * Creates the given Path as a brand-new zero-length file.  If
     * create fails, or if it already existed, return false.
     *
     * @param f
     *     path to use for create
     */
    public boolean createNewFile(Path f) throws IOException {
      if (exists(f)) {
        return false;
      } else {
        create(f, false).close();
        return true;
      }
    }
  
    /**
     * Append to an existing file (optional operation).
     *
     * @param f
     *     the existing file to be appended.
     * @throws IOException
     */
    public abstract FSDataOutputStream append(Path f) throws IOException;
  
    /**
     * Append to an existing file (optional operation).
     * Same as append(f, bufferSize, null).
     *
     * @param f
     *     the existing file to be appended.
     * @param bufferSize
     *     the size of the buffer to be used.
     * @throws IOException
     */
    public abstract FSDataOutputStream append(Path f, int bufferSize) throws IOException;
  
    /**
     * Renames Path src to Path dst.  Can take place on local fs
     * or remote DFS.
     *
     * @param src
     *     path to be renamed
     * @param dst
     *     new path after rename
     * @return true if rename is successful
     * @throws IOException
     *     on failure
     */
    public abstract boolean rename(Path src, Path dst) throws IOException;
  
  
    /**
     * Delete a file.
     * Always recursive delete.
     *
     * @param f
     *     the path to delete.
     * @return true if delete is successful else false.
     * @throws IOException
     */
    public abstract boolean delete(Path f) throws IOException;
  
    /**
     * Non-recursive delete not supported, just for compatible with hadoop.
     */
    public boolean delete(Path f, boolean recursive) throws IOException {
      if (!recursive) {
        throw new RuntimeException("Non-recursive delete not implemented...");
      } else {
        return delete(f);
      }
    }
  
    /**
     * Check if exists.
     *
     * @param f
     *     source file
     */
    public boolean exists(Path f) throws IOException {
      try {
        return getFileStatus(f) != null;
      } catch (FileNotFoundException e) {
        return false;
      }
    }
  
    /**
     * True iff the named path is a directory.
     * Note: Avoid using this method. Instead reuse the FileStatus
     * returned by getFileStatus() or listStatus() methods.
     *
     * @param f
     *     path to check
     */
    public boolean isDirectory(Path f) throws IOException {
      try {
        return getFileStatus(f).isDirectory();
      } catch (FileNotFoundException e) {
        return false;               // f does not exist
      }
    }
  
    /**
     * True iff the named path is a regular file.
     * Note: Avoid using this method. Instead reuse the FileStatus
     * returned by getFileStatus() or listStatus() methods.
     *
     * @param f
     *     path to check
     */
    public boolean isFile(Path f) throws IOException {
      try {
        return getFileStatus(f).isFile();
      } catch (FileNotFoundException e) {
        return false;               // f does not exist
      }
    }
  
    final private static PathFilter DEFAULT_FILTER = new PathFilter() {
      @Override
      public boolean accept(Path file) {
        return true;
      }
    };
  
    /**
     * List the statuses of the files/directories in the given path if the path is
     * a directory.
     *
     * @param f
     *     given path
     * @return the statuses of the files/directories in the given patch
     * @throws FileNotFoundException
     *     when the path does not exist;
     *     IOException see specific implementation
     */
    public abstract FileStatus[] listStatus(Path f) throws FileNotFoundException,
                                                           IOException;
  
    /*
     * Filter files/directories in the given path using the user-supplied path
     * filter. Results are added to the given array <code>results</code>.
     */
    private void listStatus(ArrayList<FileStatus> results, Path f,
                            PathFilter filter) throws FileNotFoundException, IOException {
      FileStatus listing[] = listStatus(f);
      if (listing == null) {
        throw new IOException("Error accessing " + f);
      }
  
      for (int i = 0; i < listing.length; i++) {
        if (filter.accept(listing[i].getPath())) {
          results.add(listing[i]);
        }
      }
    }
  
    /**
     * Filter files/directories in the given path using the user-supplied path
     * filter.
     *
     * @param f
     *     a path name
     * @param filter
     *     the user-supplied path filter
     * @return an array of FileStatus objects for the files under the given path
     * after applying the filter
     * @throws FileNotFoundException
     *     when the path does not exist;
     *     IOException see specific implementation
     */
    public FileStatus[] listStatus(Path f, PathFilter filter)
        throws FileNotFoundException, IOException {
      ArrayList<FileStatus> results = new ArrayList<FileStatus>();
      listStatus(results, f, filter);
      return results.toArray(new FileStatus[results.size()]);
    }
  
    /**
     * Filter files/directories in the given list of paths using default
     * path filter.
     *
     * @param files
     *     a list of paths
     * @return a list of statuses for the files under the given paths after
     * applying the filter default Path filter
     * @throws FileNotFoundException
     *     when the path does not exist;
     *     IOException see specific implementation
     */
    public FileStatus[] listStatus(Path[] files)
        throws FileNotFoundException, IOException {
      return listStatus(files, DEFAULT_FILTER);
    }
  
    /**
     * Filter files/directories in the given list of paths using user-supplied
     * path filter.
     *
     * @param files
     *     a list of paths
     * @param filter
     *     the user-supplied path filter
     * @return a list of statuses for the files under the given paths after
     * applying the filter
     * @throws FileNotFoundException
     *     when the path does not exist;
     *     IOException see specific implementation
     */
    public FileStatus[] listStatus(Path[] files, PathFilter filter)
        throws FileNotFoundException, IOException {
      ArrayList<FileStatus> results = new ArrayList<FileStatus>();
      for (int i = 0; i < files.length; i++) {
        listStatus(results, files[i], filter);
      }
      return results.toArray(new FileStatus[results.size()]);
    }
  
    /**
     * Make the given file and all non-existent parents into
     * directories. Has the semantics of Unix 'mkdir -p'.
     * Existence of the directory hierarchy is not an error.
     *
     * @param f
     *     path to create
     */
    public abstract boolean mkdirs(Path f) throws IOException;
  
    /**
     * Return a file status object that represents the path.
     *
     * @param f
     *     The path we want information from
     * @return a FileStatus object
     * @throws FileNotFoundException
     *     when the path does not exist;
     *     IOException see specific implementation
     */
    public abstract FileStatus getFileStatus(Path f) throws IOException;
  
  }
  