public static void main()

in boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java [313:635]


    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException,
                    ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
                    IllegalArgumentException, InvocationTargetException {
        String javaHome = System.getProperty("java.home");
        if (javaHome != null) {
            AnsiLog.info("JAVA_HOME: " + javaHome);
        }
        Package bootstrapPackage = Bootstrap.class.getPackage();
        if (bootstrapPackage != null) {
            String arthasBootVersion = bootstrapPackage.getImplementationVersion();
            if (arthasBootVersion != null) {
                AnsiLog.info("arthas-boot version: " + arthasBootVersion);
            }
        }

        try {
            String javaToolOptions = System.getenv("JAVA_TOOL_OPTIONS");
            if (javaToolOptions != null && !javaToolOptions.trim().isEmpty()) {
                AnsiLog.info("JAVA_TOOL_OPTIONS: " + javaToolOptions);
            }
        } catch (Throwable e) {
            // ignore
        }

        Bootstrap bootstrap = new Bootstrap();

        CLI cli = CLIConfigurator.define(Bootstrap.class);
        CommandLine commandLine = cli.parse(Arrays.asList(args));

        try {
            CLIConfigurator.inject(commandLine, bootstrap);
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(usage(cli));
            System.exit(1);
        }

        if (bootstrap.isVerbose()) {
            AnsiLog.level(Level.ALL);
        }
        if (bootstrap.isHelp()) {
            System.out.println(usage(cli));
            System.exit(0);
        }

        if (bootstrap.getRepoMirror() == null || bootstrap.getRepoMirror().trim().isEmpty()) {
            bootstrap.setRepoMirror("center");
            // if timezone is +0800, default repo mirror is aliyun
            if (TimeUnit.MILLISECONDS.toHours(TimeZone.getDefault().getOffset(System.currentTimeMillis())) == 8) {
                bootstrap.setRepoMirror("aliyun");
            }
        }
        AnsiLog.debug("Repo mirror:" + bootstrap.getRepoMirror());

        if (bootstrap.isVersions()) {
            System.out.println(UsageRender.render(listVersions()));
            System.exit(0);
        }

        if (JavaVersionUtils.isJava6() || JavaVersionUtils.isJava7()) {
            bootstrap.setuseHttp(true);
            AnsiLog.debug("Java version is {}, only support http, set useHttp to true.",
                            JavaVersionUtils.javaVersionStr());
        }

        // check telnet/http port
        long telnetPortPid = -1;
        long httpPortPid = -1;
        if (bootstrap.getTelnetPortOrDefault() > 0) {
            telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPortOrDefault());
            if (telnetPortPid > 0) {
                AnsiLog.info("Process {} already using port {}", telnetPortPid, bootstrap.getTelnetPortOrDefault());
            }
        }
        if (bootstrap.getHttpPortOrDefault() > 0) {
            httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPortOrDefault());
            if (httpPortPid > 0) {
                AnsiLog.info("Process {} already using port {}", httpPortPid, bootstrap.getHttpPortOrDefault());
            }
        }

        long pid = bootstrap.getPid();
        // select pid
        if (pid < 0) {
            try {
                pid = ProcessUtils.select(bootstrap.isVerbose(), telnetPortPid, bootstrap.getSelect());
            } catch (InputMismatchException e) {
                System.out.println("Please input an integer to select pid.");
                System.exit(1);
            }
            if (pid < 0) {
                System.out.println("Please select an available pid.");
                System.exit(1);
            }
        }

        checkTelnetPortPid(bootstrap, telnetPortPid, pid);

        if (httpPortPid > 0 && pid != httpPortPid) {
            AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.",
                            pid, bootstrap.getHttpPortOrDefault());
            AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
                            httpPortPid);
            AnsiLog.error("2. Or try to use different http port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port 9999");
            System.exit(1);
        }

        // find arthas home
        File arthasHomeDir = null;
        if (bootstrap.getArthasHome() != null) {
            verifyArthasHome(bootstrap.getArthasHome());
            arthasHomeDir = new File(bootstrap.getArthasHome());
        }
        if (arthasHomeDir == null && bootstrap.getUseVersion() != null) {
            // try to find from ~/.arthas/lib
            File specialVersionDir = new File(System.getProperty("user.home"), ".arthas" + File.separator + "lib"
                            + File.separator + bootstrap.getUseVersion() + File.separator + "arthas");
            if (!specialVersionDir.exists()) {
                // try to download arthas from remote server.
                DownloadUtils.downArthasPackaging(bootstrap.getRepoMirror(), bootstrap.isUseHttp(),
                                bootstrap.getUseVersion(), ARTHAS_LIB_DIR.getAbsolutePath());
            }
            verifyArthasHome(specialVersionDir.getAbsolutePath());
            arthasHomeDir = specialVersionDir;
        }

        // Try set the directory where arthas-boot.jar is located to arthas home
        if (arthasHomeDir == null) {
            CodeSource codeSource = Bootstrap.class.getProtectionDomain().getCodeSource();
            if (codeSource != null) {
                try {
                    // https://stackoverflow.com/a/17870390
                    File bootJarPath = new File(codeSource.getLocation().toURI().getSchemeSpecificPart());
                    verifyArthasHome(bootJarPath.getParent());
                    arthasHomeDir = bootJarPath.getParentFile();
                } catch (Throwable e) {
                    // ignore
                }

            }
        }

        // try to download from remote server
        if (arthasHomeDir == null) {
            boolean checkFile =  ARTHAS_LIB_DIR.exists() || ARTHAS_LIB_DIR.mkdirs();
            if(!checkFile){
                AnsiLog.error("cannot create directory {}: maybe permission denied", ARTHAS_LIB_DIR.getAbsolutePath());
                System.exit(1);
            }

            /**
             * <pre>
             * 1. get local latest version
             * 2. get remote latest version
             * 3. compare two version
             * </pre>
             */
            List<String> versionList = listNames(ARTHAS_LIB_DIR);
            Collections.sort(versionList);

            String localLatestVersion = null;
            if (!versionList.isEmpty()) {
                localLatestVersion = versionList.get(versionList.size() - 1);
            }

            String remoteLatestVersion = DownloadUtils.readLatestReleaseVersion();

            boolean needDownload = false;
            if (localLatestVersion == null) {
                if (remoteLatestVersion == null) {
                    // exit
                    AnsiLog.error("Can not find Arthas under local: {} and remote repo mirror: {}", ARTHAS_LIB_DIR,
                            bootstrap.getRepoMirror());
                    AnsiLog.error(
                            "Unable to download arthas from remote server, please download the full package according to wiki: https://github.com/alibaba/arthas");
                    System.exit(1);
                } else {
                    needDownload = true;
                }
            } else {
                if (remoteLatestVersion != null) {
                    if (localLatestVersion.compareTo(remoteLatestVersion) < 0) {
                        AnsiLog.info("local latest version: {}, remote latest version: {}, try to download from remote.",
                                localLatestVersion, remoteLatestVersion);
                        needDownload = true;
                    }
                }
            }
            if (needDownload) {
                // try to download arthas from remote server.
                DownloadUtils.downArthasPackaging(bootstrap.getRepoMirror(), bootstrap.isUseHttp(),
                        remoteLatestVersion, ARTHAS_LIB_DIR.getAbsolutePath());
                localLatestVersion = remoteLatestVersion;
            }

            // get the latest version
            arthasHomeDir = new File(ARTHAS_LIB_DIR, localLatestVersion + File.separator + "arthas");
        }

        verifyArthasHome(arthasHomeDir.getAbsolutePath());

        AnsiLog.info("arthas home: " + arthasHomeDir);

        if (telnetPortPid > 0 && pid == telnetPortPid) {
            AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPortOrDefault());
        } else {
            //double check telnet port and pid before attach
            telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPortOrDefault());
            checkTelnetPortPid(bootstrap, telnetPortPid, pid);
            if (telnetPortPid > 0 && pid == telnetPortPid) {
                AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPortOrDefault());
            } else {

                // start arthas-core.jar
                List<String> attachArgs = new ArrayList<String>();
                attachArgs.add("-jar");
                attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
                attachArgs.add("-pid");
                attachArgs.add("" + pid);
                if (bootstrap.getTargetIp() != null) {
                    attachArgs.add("-target-ip");
                    attachArgs.add(bootstrap.getTargetIp());
                }

                if (bootstrap.getTelnetPort() != null) {
                    attachArgs.add("-telnet-port");
                    attachArgs.add("" + bootstrap.getTelnetPort());
                }

                if (bootstrap.getHttpPort() != null) {
                    attachArgs.add("-http-port");
                    attachArgs.add("" + bootstrap.getHttpPort());
                }

                attachArgs.add("-core");
                attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
                attachArgs.add("-agent");
                attachArgs.add(new File(arthasHomeDir, "arthas-agent.jar").getAbsolutePath());
                if (bootstrap.getSessionTimeout() != null) {
                    attachArgs.add("-session-timeout");
                    attachArgs.add("" + bootstrap.getSessionTimeout());
                }

                if (bootstrap.getAppName() != null) {
                    attachArgs.add("-app-name");
                    attachArgs.add(bootstrap.getAppName());
                }

                if (bootstrap.getUsername() != null) {
                    attachArgs.add("-username");
                    attachArgs.add(bootstrap.getUsername());
                }
                if (bootstrap.getPassword() != null) {
                    attachArgs.add("-password");
                    attachArgs.add(bootstrap.getPassword());
                }

                if (bootstrap.getTunnelServer() != null) {
                    attachArgs.add("-tunnel-server");
                    attachArgs.add(bootstrap.getTunnelServer());
                }
                if (bootstrap.getAgentId() != null) {
                    attachArgs.add("-agent-id");
                    attachArgs.add(bootstrap.getAgentId());
                }
                if (bootstrap.getStatUrl() != null) {
                    attachArgs.add("-stat-url");
                    attachArgs.add(bootstrap.getStatUrl());
                }

                if (bootstrap.getDisabledCommands() != null) {
                    attachArgs.add("-disabled-commands");
                    attachArgs.add(bootstrap.getDisabledCommands());
                }

                AnsiLog.info("Try to attach process " + pid);
                AnsiLog.debug("Start arthas-core.jar args: " + attachArgs);
                ProcessUtils.startArthasCore(pid, attachArgs);

                AnsiLog.info("Attach process {} success.", pid);
            }
        }

        if (bootstrap.isAttachOnly()) {
            System.exit(0);
        }

        // start java telnet client
        // find arthas-client.jar
        URLClassLoader classLoader = new URLClassLoader(
                        new URL[] { new File(arthasHomeDir, "arthas-client.jar").toURI().toURL() });
        Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
        Method mainMethod = telnetConsoleClas.getMethod("main", String[].class);
        List<String> telnetArgs = new ArrayList<String>();

        if (bootstrap.getCommand() != null) {
            telnetArgs.add("-c");
            telnetArgs.add(bootstrap.getCommand());
        }
        if (bootstrap.getBatchFile() != null) {
            telnetArgs.add("-f");
            telnetArgs.add(bootstrap.getBatchFile());
        }
        if (bootstrap.getHeight() != null) {
            telnetArgs.add("--height");
            telnetArgs.add("" + bootstrap.getHeight());
        }
        if (bootstrap.getWidth() != null) {
            telnetArgs.add("--width");
            telnetArgs.add("" + bootstrap.getWidth());
        }

        // telnet port ,ip
        telnetArgs.add(bootstrap.getTargetIpOrDefault());
        telnetArgs.add("" + bootstrap.getTelnetPortOrDefault());

        AnsiLog.info("arthas-client connect {} {}", bootstrap.getTargetIpOrDefault(), bootstrap.getTelnetPortOrDefault());
        AnsiLog.debug("Start arthas-client.jar args: " + telnetArgs);

        // fix https://github.com/alibaba/arthas/issues/833
        Thread.currentThread().setContextClassLoader(classLoader);
        mainMethod.invoke(null, new Object[] { telnetArgs.toArray(new String[0]) });
    }