com.thoughtworks.go.agent.bootstrapper.AgentBootstrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.thoughtworks.go.agent.bootstrapper.AgentBootstrapper.java

Source

/*
 * Copyright 2019 ThoughtWorks, Inc.
 *
 * Licensed 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.thoughtworks.go.agent.bootstrapper;

import com.thoughtworks.cruise.agent.common.launcher.AgentLauncher;
import com.thoughtworks.go.agent.common.AgentBootstrapperArgs;
import com.thoughtworks.go.agent.common.AgentCLI;
import com.thoughtworks.go.agent.common.util.Downloader;
import com.thoughtworks.go.logging.LogConfigurator;
import com.thoughtworks.go.util.FileUtil;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.util.SystemUtil;
import com.thoughtworks.go.util.validators.FileValidator;
import com.thoughtworks.go.util.validators.Validation;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

import static com.thoughtworks.go.utils.AssertJava8.assertVMVersion;

public class AgentBootstrapper {

    private static final int DEFAULT_WAIT_TIME_BEFORE_RELAUNCH_IN_MS = 10000;
    public static final String WAIT_TIME_BEFORE_RELAUNCH_IN_MS = "agent.bootstrapper.wait.time.before.relaunch.in.ms";
    public static final String DEFAULT_LOGBACK_CONFIGURATION_FILE = "agent-bootstrapper-logback.xml";
    public static final RegexFileFilter AGENT_LAUNCHER_TMP_FILE_FILTER = new RegexFileFilter(
            "([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})agent-launcher.jar",
            IOCase.INSENSITIVE);

    int waitTimeBeforeRelaunch = SystemUtil.getIntProperty(WAIT_TIME_BEFORE_RELAUNCH_IN_MS,
            DEFAULT_WAIT_TIME_BEFORE_RELAUNCH_IN_MS);
    private static final Logger LOG = LoggerFactory.getLogger(AgentBootstrapper.class);

    private boolean loop;

    private Thread launcherThread;

    public AgentBootstrapper() {
    }

    public static void main(String[] argv) {
        assertVMVersion();
        AgentBootstrapperArgs args = new AgentCLI().parse(argv);
        new LogConfigurator(DEFAULT_LOGBACK_CONFIGURATION_FILE)
                .runWithLogger(() -> new AgentBootstrapper().go(true, args));
    }

    public void go(boolean shouldLoop, AgentBootstrapperArgs bootstrapperArgs) {
        loop = shouldLoop;
        launcherThread = Thread.currentThread();

        validate();
        cleanupTempFiles();

        int returnValue = 0;
        DefaultAgentLaunchDescriptorImpl descriptor = new DefaultAgentLaunchDescriptorImpl(bootstrapperArgs, this);

        do {
            ClassLoader tccl = launcherThread.getContextClassLoader();
            try (AgentLauncherCreator agentLauncherCreator = getLauncherCreator()) {
                AgentLauncher launcher = agentLauncherCreator.createLauncher();
                LOG.info("Attempting create and start launcher...");
                setContextClassLoader(launcher.getClass().getClassLoader());
                returnValue = launcher.launch(descriptor);
                resetContextClassLoader(tccl);
                LOG.info("Launcher returned with code {}(0x{})", returnValue,
                        Integer.toHexString(returnValue).toUpperCase());
                if (returnValue == AgentLauncher.IRRECOVERABLE_ERROR) {
                    loop = false;
                }
            } catch (Exception e) {
                LOG.error("Error starting launcher", e);
            } finally {
                resetContextClassLoader(tccl);
                forceGCToPreventOOM();
            }
            waitForRelaunchTime();
        } while (loop);

        LOG.info("Agent Bootstrapper stopped");

        jvmExit(returnValue);
    }

    private void cleanupTempFiles() {
        FileUtils.deleteQuietly(new File(FileUtil.TMP_PARENT_DIR));
        FileUtils.deleteQuietly(new File("exploded_agent_launcher_dependencies")); // launchers extracted from old versions
        FileUtils.listFiles(new File("."), AGENT_LAUNCHER_TMP_FILE_FILTER, FalseFileFilter.INSTANCE)
                .forEach(FileUtils::deleteQuietly);
        FileUtils.deleteQuietly(new File(new SystemEnvironment().getConfigDir(), "trust.jks"));
    }

    void waitForRelaunchTime() {
        LOG.info("Waiting for {} ms before re-launch....", waitTimeBeforeRelaunch);
        try {
            Thread.sleep(waitTimeBeforeRelaunch);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void forceGCToPreventOOM() {
        System.gc();
    }

    void jvmExit(int returnValue) {
        System.exit(returnValue);
    }

    private void setContextClassLoader(ClassLoader tccl) {
        Thread.currentThread().setContextClassLoader(tccl);
    }

    private void resetContextClassLoader(ClassLoader tccl) {
        Thread.currentThread().setContextClassLoader(tccl);
    }

    public void stopLooping() {
        loop = false;
    }

    void validate() {
        Validation validation = new Validation();
        FileValidator.defaultFile(Downloader.AGENT_LAUNCHER, false).validate(validation);
        if (!validation.isSuccessful()) {
            validation.logErrors(LOG);
            throw new RuntimeException("Agent Bootstrapper initialization failed. Could not validate file: "
                    + Downloader.AGENT_LAUNCHER);
        }
    }

    AgentLauncherCreator getLauncherCreator() {
        return new DefaultAgentLauncherCreatorImpl();
    }
}