package org.jenkinsci.plugins.ondemandslave;


import com.google.common.base.Strings;
import hudson.*;
import hudson.model.Descriptor;
import hudson.model.TaskListener;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.DelegatingComputerLauncher;
import hudson.slaves.SlaveComputer;
import hudson.tasks.Shell;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Implements the custom logic for an on-demand slave, executing scripts before connecting and after disconnecting
 */
public class OnDemandSlaveLauncher extends DelegatingComputerLauncher {

    private final String startScript;
    private final String stopScript;

    @DataBoundConstructor
    public OnDemandSlaveLauncher(ComputerLauncher launcher,
                          String startScript,
                          String stopScript) {
        super(launcher);
        this.startScript = startScript;
        this.stopScript = stopScript;
    }

    /**
     * Executes a script on the master node, with a bit of tracing.
     */
    private void execute(String script, TaskListener listener) throws IOException, InterruptedException {
        Jenkins jenkins = Jenkins.getInstance();

        if (jenkins == null) {
            listener.getLogger().println("Jenkins is not ready... doing nothing");
            return;
        }

        if (Strings.isNullOrEmpty(script)) {
            listener.getLogger().println("No script to be executed for this on-demand slave.");
            return;
        }

            Launcher launcher = jenkins.getRootPath().createLauncher(listener);
            Shell shell = new Shell(script);
            FilePath root = jenkins.getRootPath();
            FilePath scriptFile = shell.createScriptFile(root);
            int r = launcher.launch().cmds(shell.buildCommandLine(scriptFile)).stdout(listener).join();

            if (r != 0) {
                throw new AbortException("Script failed with return code " + Integer.toString(r) + ".");
            }

            listener.getLogger().println("Script executed successfully.");

    }

    /*
     * Getters for Jelly
     */
    public String getStartScript() {
        return startScript;
    }

    public String getStopScript() {
        return stopScript;
    }

    /*
     *  Delegated methods that plug the additional logic for on-demand slaves
     */

    @Override
    public void launch(SlaveComputer computer, TaskListener listener) throws IOException, InterruptedException {
        execute(startScript, listener);
        super.launch(computer, listener);
    }

    @Override
    public void afterDisconnect(SlaveComputer computer, TaskListener listener) {
        super.afterDisconnect(computer, listener);

        try {
            execute(stopScript, listener);
        }  catch (Exception e) {
            listener.getLogger().println("Failed executing script '" + stopScript + "'.");
            e.printStackTrace(listener.getLogger());
        }
    }

    @Extension
    public static class DescriptorImpl extends Descriptor<ComputerLauncher> {

        public String getDisplayName() {
            return "Start and stop this node on-demand";
        }

        /**
         * Returns the applicable nested computer launcher types.
         * The default implementation avoids all delegating descriptors, as that creates infinite recursion.
         */
        public List<Descriptor<ComputerLauncher>> getApplicableDescriptors() {
            List<Descriptor<ComputerLauncher>> r = new ArrayList<>();
            for (Descriptor<ComputerLauncher> d : Functions.getComputerLauncherDescriptors()) {
                if (DelegatingComputerLauncher.class.isAssignableFrom(d.getKlass().toJavaClass()))  continue;
                r.add(d);
            }
            return r;
        }
    }

}

@@ -424,59 +424,8 @@
 ion;
-%0Aimport java.util.ArrayList;%0Aimport java.util.List;
 %0A%0A/*
@@ -3097,17 +3097,16 @@
 cher%3E %7B%0A
-%0A
         
@@ -3208,635 +3208,8 @@
    %7D
-%0A%0A        /**%0A         * Returns the applicable nested computer launcher types.%0A         * The default implementation avoids all delegating descriptors, as that creates infinite recursion.%0A         */%0A        public List%3CDescriptor%3CComputerLauncher%3E%3E getApplicableDescriptors() %7B%0A            List%3CDescriptor%3CComputerLauncher%3E%3E r = new ArrayList%3C%3E();%0A            for (Descriptor%3CComputerLauncher%3E d : Functions.getComputerLauncherDescriptors()) %7B%0A                if (DelegatingComputerLauncher.class.isAssignableFrom(d.getKlass().toJavaClass()))  continue;%0A                r.add(d);%0A            %7D%0A            return r;%0A        %7D
 %0A   

Remove workaround for JENKINS-35198 now it's fixed