Package org.jano

Source Code of org.jano.CommandLineParser$BasicCommandParser

package org.jano;

import org.jano.security.Right;
import org.jano.security.Rights;

import java.util.*;
import java.util.regex.Pattern;

/**
* Recognizes and translates command line arguments to server config object
*/
public class CommandLineParser {
  private final JanoConfig config;
  private CommandParser currentParser;
  private Map<String, CommandDefinition> commandMap = new HashMap<String, CommandDefinition>();
  private CommandDefinition[] commands = new CommandDefinition[] {
      new MountCommandDefinition(),
    new PortCommandDefinition(),
    new HostCommandDefinition()
  };

  public CommandLineParser(JanoConfig config) {
    this.config = config;
    this.currentParser = new BasicCommandParser();

    //index commands
    for (CommandDefinition definition : commands) {
      for (String key : definition.keys()) {
        commandMap.put(key, definition);
      }
    }
  }

  /**
   * Parses command line arguments and applies them to captured config
   * @return config object with applied arguments
   */
  public JanoConfig parse(String[] args) {
    boolean awaitCommand = false;
    for (String arg : args) {
      if (awaitCommand) {
        currentParser.processArgument(arg);
      } else {
        CommandDefinition nextCommand = commandMap.get(arg);
        if (null == nextCommand) {
          currentParser.processArgument(arg);
        } else {
          currentParser.finish();
          currentParser = nextCommand.createParser();
        }
      }
      awaitCommand = currentParser.isNextRequired();
    }

    currentParser.finish();

    return config;
  }

  interface CommandParser {
    /** Notifies scanner that command awaits required parameter */
    boolean isNextRequired();
    /** Processes next argument */
    void processArgument(String arg);
    /** Notifies parser that no more fragments will be send */
    void finish();
  }

  interface CommandDefinition {
    /** Exposes legal command triggers */
    String[] keys();
    /** Provides quick help string */
    String help();
    /** Creates parser for new ocurrense of command */
    CommandParser createParser();
  }

  class BasicCommandParser implements CommandParser {
    @Override
    public boolean isNextRequired() {
      return false;
    }

    @Override
    public void processArgument(String arg) {
      try {
        new PortCommandDefinition().createParser().processArgument(arg);
      } catch (CommandParseException e1) {
        try {
          new HostCommandDefinition().createParser().processArgument(arg);
        } catch (CommandParseException e2) {
          ;//follow in deep
          throw new CommandParseException("Invalid quick parameter '" + arg + "'. You can specify port number or/and host");
        }
      }
    }

    @Override
    public void finish() { }
  }

  /**
   * Implementation of PORT command
   */
  class PortCommandDefinition implements CommandDefinition {
    @Override
    public String[] keys() {
      return new String[] { "-p", "--port" };
    }

    @Override
    public String help() {
      return "Overrides a listening port for server. Default port is 80.";
    }

    @Override
    public CommandParser createParser() {
      return new CommandParser() {
        boolean done = false;
        @Override
        public boolean isNextRequired() {
          return !done;
        }

        @Override
        public void processArgument(String arg) {
          try {
            int port = Integer.parseInt(arg);
            if (port >= 1 && port <= 65535) {
              config.port(port);
              done = true;
            } else {
              throw new CommandParseException("Invalid port number " + port + ". Should be 1 .. 65535");
            }
          } catch (NumberFormatException e) {
            throw new CommandParseException("Value '" + arg + "' is not valid port number");
          }
        }

        @Override
        public void finish() { }
      };
    }
  }

  /**
   * Implementation of HOST command
   */
  class HostCommandDefinition implements CommandDefinition {
    private final Pattern hostNamePattern = Pattern.compile("^(([a-z]|[a-z][a-z0-9\\-]*[a-z0-9])\\.)*([a-z]|[a-z][a-z0-9\\-]*[a-z0-9])$", Pattern.CASE_INSENSITIVE);

    @Override
    public String[] keys() {
      return new String[] { "-h", "--host" };
    }

    @Override
    public String help() {
      return "Forces processing of requests with specified HTTP host.";
    }

    @Override
    public CommandParser createParser() {
      return new CommandParser() {
        boolean done = false;
        @Override
        public boolean isNextRequired() {
          return !done;
        }

        @Override
        public void processArgument(String arg) {
          if (hostNamePattern.matcher(arg).matches()) {
            config.hostname(arg);
            done = true;
          } else {
            throw new CommandParseException("Invalid host name '" + arg + "'");
          }
        }

        @Override
        public void finish() { }
      };


    }

  }

  /**
   * Implementation of MOUNT command
   */
  class MountCommandDefinition implements CommandDefinition {
    @Override
    public String[] keys() {
      return new String[] { "-m", "--mount" };
    }

    @Override
    public String help() {
      return "Mounts file system resource as server resource with some rights. E.g. --mount /path_to_application /app ?";
    }

    @Override
    public CommandParser createParser() {
      return new CommandParser() {
        String resource;
        String point = "/";
        Set<Right> rights;

        @Override
        public boolean isNextRequired() {
          return null == resource;
        }

        @Override
        public void processArgument(String arg) {
          //resource is mandatory
          if (null == resource) {
            resource = arg;
            String maybePoint = toMountPoint(arg);
            if (null != maybePoint) {
              point = maybePoint;
            }
          } else {
            String asMountPoint = toMountPoint(arg);
            if (null != asMountPoint) {
              point = asMountPoint;
            } else {
              if (null == rights) {
                rights = parseRights(arg);
              } else {
                throw new CommandParseException("Unexpected parameter '" + arg + "' for command --mount");
              }
            }
          }
        }

        @Override
        public void finish() {
          if (null == point) throw new CommandParseException("Mount point for resource '" + resource + "' is not specified");
          config.mountFileView(point, resource, null != rights ? rights : Rights.all);
        }

        private String toMountPoint(String uri) {
          return uri.startsWith(Uri.ROOT) ? uri : null;
        }

        private Set<Right> parseRights(String attrs) {
          Set<Right> rights = new HashSet<Right>();
          boolean reverse = attrs.startsWith("!");
          if (reverse) {
            rights.addAll(Rights.all);
            attrs = attrs.substring(1);
          }


          for (char attr : attrs.toCharArray()) {
            Right right = Rights.bySymbol(attr);
            if (null != right) {
              if (reverse) {
                rights.remove(right);
              } else {
                rights.add(right);
              }
            } else {
              throw new CommandParseException("Unknown access rights attribute '" + attr + "'");
            }
          }

          return rights;
        }
      };
    }

  }

  /**
   * Defines exceptional situation when parsing command line arguments
   */
  public static class CommandParseException extends RuntimeException {
    public CommandParseException() {
    }

    public CommandParseException(String message) {
      super(message);
    }

    public CommandParseException(String message, Throwable cause) {
      super(message, cause);
    }
  }
}
TOP

Related Classes of org.jano.CommandLineParser$BasicCommandParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.