All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.v5.cli.spi.ArgsBase Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.v5.cli.spi;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.BindException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import com.caucho.v5.cli.command.CommandExit;
import com.caucho.v5.cli.command.HelpCommand;
import com.caucho.v5.cli.command.CommandVersion;
import com.caucho.v5.cli.server.BootArgumentException;
import com.caucho.v5.cli.shell_old.EnvCliOld;
import com.caucho.v5.cli.spi.OptionCommandLine.ArgsType;
import com.caucho.v5.config.ConfigException;
import com.caucho.v5.config.Configs;
import com.caucho.v5.config.UserMessage;
import com.caucho.v5.health.shutdown.ExitCode;
import com.caucho.v5.loader.EnvLoader;
import com.caucho.v5.loader.EnvironmentClassLoader;
import com.caucho.v5.util.CauchoUtil;
import com.caucho.v5.util.CurrentTime;
import com.caucho.v5.util.L10N;
import com.caucho.v5.util.Version;
import com.caucho.v5.vfs.PathImpl;
import com.caucho.v5.vfs.VfsOld;
import com.caucho.v5.vfs.WriteStream;

import io.baratine.config.Config;

public class ArgsBase
{
  private static L10N L = new L10N(ArgsBase.class);

  private static final Logger log
    = Logger.getLogger(ArgsBase.class.getName());

  private static final CommandManager _managerCommandLine;

  private final String[] _argv;
  
  private final ProgramInfo _programInfo;
  
  private final long _startTime;
  
  private final EnvCliOld _env;
  
  private final Config.ConfigBuilder _envBuilder = Configs.config();

  private HashMap _valueMap = new HashMap<>();
  private ArrayList _tailArgs = new ArrayList<>();
  
  private String []_defaultArgs;
  
  private Command _command;
  
  private PathImpl _javaHome;
  private PathImpl _homeDirectory;
  
  private boolean _isVerbose;
  private boolean _isQuiet;
  private boolean _isHelp;

  private boolean _is64bit;
  
  /**
   * For the commandManager init.
   */
  protected ArgsBase()
  {
    _argv = null;
    _startTime = 0;
    
    _programInfo = null;
    _env = null;
  }

  public ArgsBase(String[] argv, ProgramInfo programInfo)
  {
    this(new EnvCliOld(), argv, programInfo);
  }
  
  public ArgsBase(EnvCliOld env, String[] argv, ProgramInfo programInfo)
  {
    Objects.requireNonNull(env);
    Objects.requireNonNull(argv);
    Objects.requireNonNull(programInfo);
    
    _env = env;
    _programInfo = programInfo;
    
    _startTime = CurrentTime.currentTime();
    
    _argv = fillArgv(argv);

    initDefaults();
  }
  
  public EnvCliOld envCli()
  {
    return _env;
  }
  
  public WriteStream getOut()
  {
    return envCli().getOut();
  }
  
  protected boolean isEmbedded()
  {
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
  
    return (loader instanceof EnvironmentClassLoader);
  }

  public void property(String envName, String value)
  {
    _envBuilder.add(envName, value);
  }
  
  public Config config()
  {
    return _envBuilder.get();
  }
  
  public void config(Config env)
  {
    _envBuilder.add(env);
  }


  public ExitCode parse()
  {
    CommandLineParser parser = new CommandLineParser();
    
    return parser.parseCommandLine(this);
  }

  public void copyFrom(ArgsBase args)
  {
    _isQuiet = args._isQuiet;
    _isVerbose = args._isVerbose;
  }

  public ExitCode doCommand()
  {
    ExitCode code = parse();
    
    if (code != ExitCode.OK) {
      return code;
    }
    
    Command command = (Command) getCommand();
    
    return command.doCommand(this);
  }
  
  public void doMain()
  {
    try {
      envCli().initLogging();
      initHomeClassPath();
      
      final String jvmVersion = System.getProperty("java.runtime.version");

      if ("1.8".compareTo(jvmVersion) > 0) {
        throw new ConfigException(L.l("{0} requires Java 1.8 or later but was started with {1}",
                                      getDisplayName(), jvmVersion));
      }

      ExitCode code = doCommand();

      envCli().exit(code);
    } catch (BootArgumentException e) {
      printException(e);

      envCli().exit(ExitCode.UNKNOWN_ARGUMENT);
    } catch (ConfigException e) {
      printException(e);

      envCli().exit(ExitCode.BAD_CONFIG);
    } catch (Exception e) {
      Throwable cause;
      
      for (cause = e;
           cause != null && cause.getCause() != null;
           cause = cause.getCause()) {
        if (cause instanceof UserMessage) {
          break;
        }
      }
      
      if (cause instanceof BindException) {
        System.err.println(e.getMessage());

        log.severe(e.toString());

        log.log(Level.FINE, e.toString(), e);

        envCli().exit(ExitCode.BIND);
      }

      printException(e);
      
      envCli().exit(ExitCode.UNKNOWN);
    }
  }

  private void printException(Throwable e)
  {
    System.err.println(e.getMessage());

    if (e.getMessage() == null
        || isVerbose()) {
      e.printStackTrace();
    }
  }
  
  protected ProgramInfo getProgramInfo()
  {
    return _programInfo;
  }
  
  public final String getProgramName()
  {
    return getProgramInfo().getProgramName();
  }
  
  public final String getCommandName()
  {
    return getProgramInfo().getCommandName();
  }
  
  protected final String getMainJarName()
  {
    return getProgramInfo().getMainJarName();
  }
  
  public final String getDisplayName()
  {
    return getProgramInfo().getDisplayName();
  }

  public String []getRawArgv()
  {
    return _argv;
  }

  public PathImpl getJavaHome()
  {
    return _javaHome;
  }

  public PathImpl getHomeDirectory()
  {
    return _homeDirectory;
  }

  public String[] getArgv()
  {
    return _argv;
  }

  public boolean isVerbose()
  {
    return _isVerbose;
  }

  public boolean isQuiet()
  {
    return _isQuiet;
  }

  public void setQuiet(boolean isQuiet)
  {
    _isQuiet = isQuiet;
  }

  protected void setHomeDirectory(PathImpl homeDirectory)
  {
    _homeDirectory = homeDirectory;

    System.setProperty(getProgramName() + ".home", 
                       homeDirectory.getNativePath());
  }

  public boolean is64Bit()
  {
    return _is64bit;
  }

  public Command getCommand()
  {
    return _command;
  }

  public void setCommand(Command command)
  {
    _command = command;
  }
  
  public OptionCommandLine getOption(String name)
  {
    return getCommandManager().getOption(name);
  }
  
  public void addOption(String name, ArgValueCli value)
  {
    _valueMap.put(name, value);
  }
  
  public long getStartTime()
  {
    return _startTime;
  }

  /**
   * Adds an arg after the command and any options.
   */
  public void addTailArg(String arg)
  {
    _tailArgs.add(arg);
  }

  public ArrayList getTailArgs()
  {
    return _tailArgs;
  }

  public String getTail(int index)
  {
    if (index < _tailArgs.size()) {
      return _tailArgs.get(index);
    }
    else {
      return null;
    }
  }

  public void setDefaultArgs(String[] args)
  {
    _defaultArgs = args;
  }

  public String []getDefaultArgs()
  {
    return _defaultArgs;
  }

  public boolean isHelp()
  {
    return _isHelp;
  }

  public void setHelp(boolean isHelp)
  {
    _isHelp = isHelp;
  }

  public void set64Bit(boolean isSet)
  {
    _is64bit = isSet;
  }

  public void setVerbose(boolean isSet)
  {
    _isVerbose = isSet;
    
    if (isSet) {
      Logger.getLogger("").setLevel(Level.CONFIG);
    }
  }

  public Map> getCommandMap()
  {
    return (Map) getCommandManager().getCommandMap();
  }

  protected void initDefaults()
  {
    _javaHome = VfsOld.lookup(System.getProperty("java.home"));

    _is64bit = CauchoUtil.is64Bit();

    setHomeDirectory(calculateHomeDirectory());
  }
  
  public void initHomeClassPath()
  {
    try {
      ClassLoader loader = getClass().getClassLoader();

      if (loader instanceof URLClassLoader) {
        URLClassLoader urlLoader = (URLClassLoader) loader;
        
        Method addURL = findAddURL();

        PathImpl lib = getHomeDirectory().lookup("lib");
        String classPath = System.getProperty("java.class.path");
        
        for (String file : lib.list()) {
          if (classPath.contains(file)) {
            continue;
          }
          
          try {
            URL url = new URL("file://" + lib.lookup(file).getFullPath());

            addURL.invoke(urlLoader, url);
          } catch (Exception e) {
            System.err.println("Exn: " + e);
          }
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  private static Method findAddURL()
  {
    for (Method method : URLClassLoader.class.getDeclaredMethods()) {
      if (method.getName().equals("addURL")
          && method.getParameterTypes().length == 1) {
        method.setAccessible(true);
        
        return method;
      }
    }
    
    return null;
  }

  protected void init()
  {
  }
  
  public String getArg(String arg)
  {
    ArgValueCli value = _valueMap.get(arg);
    
    if (value != null) {
      return value.getString();
    }
    else {
      // return getArgImpl(arg);
      
      return null;
    }
  }
  
  public String getArg(String arg, String valueDefault)
  {
    ArgValueCli value = _valueMap.get(arg);
    
    if (value != null) {
      return value.getString();
    }
    else {
      // return getArgImpl(arg);
      
      return valueDefault;
    }
  }
  
  public Iterable getArgList(String arg)
  {
    ArgValueCli value = _valueMap.get(arg);
    
    if (value != null) {
      return value.getList();
    }
    else {
      return new ArrayList<>();
    }
  }

  public String getArgImpl(String arg)
  {
    for (int i = 0; i + 1 < _argv.length; i++) {
      if (_argv[i].equals(arg) || _argv[i].equals("-" + arg)) {
        return _argv[i + 1];
      }
    }

    return null;
  }

  public boolean getArgFlag(String arg)
  {
    ArgValueCli value = _valueMap.get(arg);
    
    if (value != null) {
      return value.getBoolean();
    }
    else {
      return false;
    }
  }

  public boolean getArgBoolean(String arg)
  {
    return getArgBoolean(arg, false);
  }
  
  public boolean getArgBoolean(String arg, boolean defaultValue)
  {
    String value = getArg(arg);

    if (value == null) {
      return defaultValue;
    }

    if ("no".equals(value) || "false".equals(value)) {
      return false;
    }
    else {
      return true;
    }
  }

  public int getArgInt(String arg, int defaultValue)
  {
    String value = getArg(arg);

    if (value == null) {
      return defaultValue;
    }

    try {
      return Integer.parseInt(value);
    } catch (NumberFormatException e) {
      BootArgumentException e1
        = new BootArgumentException(L.l("{0} argument is not a number '{1}'",
                                        arg, value));
      e1.setStackTrace(e.getStackTrace());

      throw e1;
    }
  }

  public double getArgDouble(String arg, double defaultValue)
  {
    String value = getArg(arg);

    if (value == null)
      return defaultValue;

    try {
      return Double.parseDouble(value);
    } catch (NumberFormatException e) {
      BootArgumentException e1
        = new BootArgumentException(L.l("{0} argument is not a number '{1}'",
                                        arg, value));
      e1.setStackTrace(e.getStackTrace());

      throw e;
    }
  }

  public boolean hasOption(String option)
  {
    for (String arg : _argv) {
      if (option.equals(arg)) {
        return true;
      }
    }

    return false;
  }

  /**
   * finds first argument that follows no dash prefixed token
   * @return
   */
  public String getDefaultArg()
  {
    String defaultArg = null;

    if (_defaultArgs.length > 0) {
      defaultArg = _defaultArgs[0];
    }

    return defaultArg;
  }
  
  public CommandManager getCommandManager()
  {
    return _managerCommandLine;
  }

  //
  // Utility static methods
  //

  String []fillArgv(String []argv)
  {
    ArrayList args = new ArrayList();

    EnvLoader.init();

    String []jvmArgs = getJvmArgs();

    if (jvmArgs != null) {
      for (int i = 0; i < jvmArgs.length; i++) {
        String arg = jvmArgs[i];

        if (args.contains(arg)) {
          continue;
        }
        
        if (arg.startsWith("-Djava.class.path=")) {
          // IBM JDK
        }
        else if (arg.startsWith("-D")) {
          int eqlSignIdx = arg.indexOf('=');
          if (eqlSignIdx == -1) {
            args.add("-J" + arg);
          } else {
            String key = arg.substring(2, eqlSignIdx);
            String value = System.getProperty(key);

            if (value == null)
              value = "";

            args.add("-J-D" + key + "=" + value);
          }
        }
      }
    }

    for (int i = 0; i < argv.length; i++) {
      args.add(argv[i]);
    }

    argv = new String[args.size()];

    args.toArray(argv);

    return argv;
  }
  
  String []getJvmArgs()
  {
    try {
      MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
      ObjectName name = new ObjectName("java.lang:type=Runtime");
      
      return (String []) mbeanServer.getAttribute(name, "InputArguments");
    } catch (Exception e) {
      log.log(Level.FINE, e.toString(), e);
      
      return null;
    }
    
  }

  PathImpl calculateHomeDirectory()
  {
    return calculateHomeDirectory(getMainJarName());
  }
  
  PathImpl calculateHomeDirectory(String jarFile)
  {
    String homePath = System.getProperty(getProgramName() + ".home");
    
    if (homePath != null) {
      return VfsOld.lookup(homePath);
    }

    // find the resin.jar as described by the classpath
    // this may differ from the value given by getURL() because getURL()
    // unwinds symbolic links.
    String classPath = System.getProperty("java.class.path");

    if (jarFile != null && classPath.indexOf(jarFile) >= 0) {
      int q = classPath.indexOf(jarFile) + jarFile.length();
      int p = classPath.lastIndexOf(File.pathSeparatorChar, q - 1);

      String mainJar;

      if (p >= 0) {
        mainJar = classPath.substring(p + 1, q);
      }
      else {
        mainJar = classPath.substring(0, q);
      }
      
      PathImpl jar = VfsOld.lookup(mainJar);

      if (jar.canRead()) {
        PathImpl libDir = jar.getParent();
        PathImpl homeDir = libDir.getParent();

        
        if (homeDir.lookup("lib").equals(libDir)) {
          return homeDir;
        }
        else {
          return libDir;
        }
      }
    }

    PathImpl pwd = CauchoUtil.getHomeDir();
    
    if (pwd != null) {
      return pwd;
    }

    throw new RuntimeException(L.l("{0}/{1}: can't discover home.dir for {2} in {3}",
                                   getDisplayName(),
                                   Version.getVersion(),
                                   CauchoUtil.class.getName()));
  }
  
  protected void initCommands(CommandManager manager)
  {
    /*
    manager.addOption(new HomeDir()).alias("home-directory")
           .alias(getProgramName() + "-home")
           .alias("-" + getProgramName() + "-home");
           */
    manager.addOption(new HomeDir()).alias("home-directory");

    manager.addOption(new VerboseFine()).tiny("v").type(ArgsType.DEBUG);
    manager.addOption(new VerboseFiner()).tiny("vv").type(ArgsType.DEBUG);
    manager.addOption(new VerboseFinest()).hide().tiny("vvv").type(ArgsType.DEBUG);
    manager.addOption(new VerboseInfo()).hide().tiny("vi").type(ArgsType.DEBUG);
    
    manager.addOption(new Quiet()).hide().type(ArgsType.DEBUG);

    manager.addCommand(new CommandVersion());
    manager.addCommand(new HelpCommand());
    manager.addCommand(new CommandExit()); // XXX: .hide();
  }
  
  static class HomeDir extends OptionCommandLine.Base
  {
    @Override
    public String getDescription()
    {
      return "installation directory";
    }
    
    @Override
    public String getValueDescription()
    {
      return "DIR";
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
      throws CommandArgumentException
    {
      args.setHomeDirectory(VfsOld.lookup(argv[index + 1]));
      argv[index + 1] = args.getHomeDirectory().getFullPath();
      
      property(args, argv[index + 1]);
      
      return index + 1;
    }
  }
  
  /**
   * --quiet disables the standard headers 
   */
  private static class Quiet extends OptionCommandLine.Base
  {
    @Override
    public boolean isFlag()
    {
      return true;
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
        throws CommandArgumentException
    {
      args.setQuiet(true);
     
      // baratine/8610
      Logger.getLogger("").setLevel(Level.OFF);

      return index;
    }
  }

  abstract private static class VerboseBase extends OptionCommandLine.Base
  {
    protected void startLogging(ArgsBase args)
      throws CommandArgumentException
    {
      args.envCli().initLogging();
    }
  }
  
  private static class VerboseInfo extends VerboseBase
  {
    public String getName()
    {
      return "verbose";
    }
    
    @Override
    public boolean isFlag()
    {
      return true;
    }
    
    @Override
    public String getDescription()
    {
      return "verbose output (fine)";
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
      throws CommandArgumentException
    {
      // args.setVerbose(true);
      Logger.getLogger("").setLevel(Level.INFO);
      
      startLogging(args);
      
      return index;
    }
  }
  
  private static class VerboseFine extends VerboseBase
  {
    public String getName()
    {
      return "verbose";
    }
    
    @Override
    public boolean isFlag()
    {
      return true;
    }
    
    @Override
    public String getDescription()
    {
      return "verbose output (fine)";
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
      throws CommandArgumentException
    {
      args.setVerbose(true);
      Logger.getLogger("").setLevel(Level.FINE);
      
      startLogging(args);
      
      return index;
    }
  }
  
  private static class VerboseFiner extends VerboseBase
  {
    @Override
    public String getName()
    {
      return "verbose-finer";
    }
    
    @Override
    public boolean isFlag()
    {
      return true;
    }
    
    @Override
    public String getDescription()
    {
      return "verbose output (finer)";
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
      throws CommandArgumentException
    {
      args.setVerbose(true);

      Logger.getLogger("").setLevel(Level.FINER);

      startLogging(args);

      return index;
    }
  }
  
  private static class VerboseFinest extends VerboseBase
  {
    @Override
    public String getName()
    {
      return "verbose-finest";
    }
    
    @Override
    public boolean isFlag()
    {
      return true;
    }
    
    @Override
    public String getDescription()
    {
      return "verbose output (finest)";
    }
    
    @Override
    public int parse(ArgsBase args, String[] argv, int index)
      throws CommandArgumentException
    {
      args.setVerbose(true);

      Logger.getLogger("").setLevel(Level.FINEST);
      
      startLogging(args);

      return index;
    }
  }

  static {
    _managerCommandLine = new CommandManager<>();
    
    ArgsBase args = new ArgsBase();
    
    args.initCommands(_managerCommandLine);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy