content: /*
   * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
   * (the "License"). You may not use this work except in compliance with the License, which is
   * available at www.apache.org/licenses/LICENSE-2.0
   *
   * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   * either express or implied, as more fully set forth in the License.
   *
   * See the NOTICE file distributed with this work for information regarding copyright ownership.
   */
  
  package alluxio.cli;
  
  import alluxio.AlluxioURI;
  import alluxio.Constants;
  import alluxio.client.file.FileSystem;
  import alluxio.client.file.URIStatus;
  import alluxio.conf.AlluxioConfiguration;
  import alluxio.conf.PropertyKey;
  import alluxio.exception.runtime.InvalidArgumentRuntimeException;
  import alluxio.exception.status.InvalidArgumentException;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.Arrays;
  import java.util.Map;
  
  /**
   * Fuse shell to run Fuse special commands.
   */
  public final class FuseShell {
    private static final Logger LOG = LoggerFactory.getLogger(FuseShell.class);
  
    private final AlluxioConfiguration mConf;
    private final FileSystem mFileSystem;
    private final Map<String, Command> mCommands;
  
    /**
     * Creates a new instance of {@link FuseShell}.
     *
     * @param fs Alluxio file system
     * @param conf the Alluxio configuration
     */
    public FuseShell(FileSystem fs, AlluxioConfiguration conf) {
      mFileSystem = fs;
      mConf = conf;
      mCommands = CommandUtils.loadCommands(FuseShell.class.getPackage().getName(),
          new Class [] {FileSystem.class, AlluxioConfiguration.class},
          new Object[] {mFileSystem, mConf});
    }
  
    /**
     * Checks if the given uri contains Fuse special command.
     *
     * @param uri check whether the uri contains Fuse special command
     * @return true if the path is a special path, otherwise false
     */
    public boolean isSpecialCommand(AlluxioURI uri) {
      int index = uri.getPath().lastIndexOf(AlluxioURI.SEPARATOR);
      return index != -1 && uri.getPath().substring(index).startsWith(Constants
          .ALLUXIO_CLI_PATH);
    }
  
    /**
     * @param uri that includes command information
     * @return a mock URIStatus instance
     */
    public URIStatus runCommand(AlluxioURI uri) {
      // TODO(bingzheng): extend some other operations.
      AlluxioURI path = uri.getParent();
      int index = uri.getPath().lastIndexOf(Constants.ALLUXIO_CLI_PATH);
      String cmdsInfo = uri.getPath().substring(index);
      String[] cmds = cmdsInfo.split("\\.");
  
      if (cmds.length <= 2) {
        logUsage();
        throw new InvalidArgumentRuntimeException("Command is needed in Fuse shell");
      }
  
      FuseCommand command = (FuseCommand) mCommands.get(cmds[2]);
      if (command == null) {
        logUsage();
        throw new InvalidArgumentRuntimeException(
            String.format("%s is an unknown command.", cmds[2]));
      }
      try {
        String [] currArgs = Arrays.copyOfRange(cmds, 2, cmds.length);
        while (command.hasSubCommand()) {
          if (currArgs.length < 2) {
            throw new InvalidArgumentRuntimeException("No sub-command is specified");
          }
          if (!command.getSubCommands().containsKey(currArgs[1])) {
            throw new InvalidArgumentRuntimeException("Unknown sub-command: " + currArgs[1]);
          }
          command = (FuseCommand) command.getSubCommands().get(currArgs[1]);
          currArgs = Arrays.copyOfRange(currArgs, 1, currArgs.length);
        }
        command.validateArgs(Arrays.copyOfRange(currArgs, 1, currArgs.length));
        return command.run(path, Arrays.copyOfRange(currArgs, 1, currArgs.length));
      } catch (InvalidArgumentException e) {
        LOG.info(command.getDescription());
        LOG.info("Usage: " + command.getUsage());
        throw new InvalidArgumentRuntimeException(String.format(
            "Invalid arguments for command %s, For detailed usage please see the log formation.",
            command.getCommandName()), e);
      }
    }
  
    private void logUsage() {
      // TODO(lu) better log fuse shell description
      LOG.info(PropertyKey.FUSE_SPECIAL_COMMAND_ENABLED.getDescription());
    }
  }
  