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

io.earcam.instrumental.agent.Attach Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * io.earcam.instrumental.agent
 * %%
 * Copyright (C) 2018 earcam
 * %%
 * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
 * 
 * You must choose to accept, in full - any individual or combination of 
 * the following licenses:
 * 
 * #L%
 */
package io.earcam.instrumental.agent;

import static java.io.File.separatorChar;
import static java.nio.charset.Charset.defaultCharset;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import com.sun.tools.attach.AgentInitializationException;  //NOSONAR these are @jdk.Exported
import com.sun.tools.attach.AgentLoadException;            //NOSONAR
import com.sun.tools.attach.AttachNotSupportedException;   //NOSONAR
import com.sun.tools.attach.VirtualMachine;                //NOSONAR

import io.earcam.instrumental.reflect.Resources;
import io.earcam.unexceptional.Closing;
import io.earcam.unexceptional.Closing.AutoClosed;
import io.earcam.utilitarian.io.IoStreams;
import io.earcam.unexceptional.Exceptional;

final class Attach {

	/**
	 * IFF {@code true}, then always attach via a separate VM
	 */
	public static final String PROPERTY_FORCE_ATTACH_TO_SELF = "io.earcam.instrumental.agent" + "forceAttachSelf";


	private Attach()
	{}


	static void attach(URI jar, String agentArguments)
			throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException, InterruptedException
	{
		if(!forceAttachToSelf() && (isJava8() || allowsAttachToSelf())) {
			VirtualMachine machine = attachToSelf();
			doLoad(machine, jar, agentArguments);
		} else {
			spawnHack(jar, agentArguments);
		}
	}


	private static void doLoad(VirtualMachine machine, URI jar, String agentArguments) throws AgentLoadException, AgentInitializationException, IOException
	{
		try(AutoClosed vm = Closing.autoClosing(machine, VirtualMachine::detach)) {
			vm.get().loadAgent(Resources.removeJarUrlDecoration(jar), agentArguments);
		}
	}


	private static void spawnHack(URI jar, String agentArguments) throws IOException, InterruptedException
	{
		List cmd = buildCommand(jar, agentArguments);

		ProcessBuilder pb = new ProcessBuilder(cmd)
				.directory(new File(System.getProperty("user.dir")));

		Process process = pb.start();
		int exitCode = process.waitFor();
		if(exitCode != 0) {
			String stdout = new String(IoStreams.readAllBytes(process.getInputStream()), defaultCharset());
			String stderr = new String(IoStreams.readAllBytes(process.getErrorStream()), defaultCharset());
			throw new IllegalStateException("Failed to spawn VM (for attach-to-self work around),\nstdout: "
					+ stdout + "\nstderr: " + stderr);
		}
	}


	private static List buildCommand(URI jar, String agentArguments)
	{
		String javaHome = System.getProperty("java.home");
		String classPath = System.getProperty("java.class.path");

		String exec = javaHome + separatorChar + "bin" + separatorChar + "java";

		RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();

		List cmd = new ArrayList<>();
		cmd.add(exec);
		cmd.add("-classpath");
		cmd.add(classPath);
		cmd.addAll(runtimeMxBean.getInputArguments());

		cmd.add(Attach.class.getCanonicalName());
		cmd.add(pid());
		cmd.add(jar.toString());
		cmd.add(agentArguments);
		return cmd;
	}


	/**
	 * 

* main. *

* * @param args an array of {@link java.lang.String} objects. * @throws java.lang.Exception if any. */ public static void main(String[] args) throws Exception { String pid = args[0]; URI jar = Exceptional.uri(args[1]); String agentArguments = args[2]; doLoad(attachTo(pid), jar, agentArguments); } private static boolean forceAttachToSelf() { return Boolean.valueOf(System.getProperty(PROPERTY_FORCE_ATTACH_TO_SELF)); } private static boolean allowsAttachToSelf() { return Boolean.valueOf(System.getProperty("jdk.attach.allowAttachSelf")); } private static boolean isJava8() { return System.getProperty("java.version").startsWith("1.8"); } private static VirtualMachine attachToSelf() throws AttachNotSupportedException, IOException { return attachTo(pid()); } private static VirtualMachine attachTo(String pid) throws AttachNotSupportedException, IOException { return VirtualMachine.attach(pid); } // Waiting on http://openjdk.java.net/jeps/102 or consider http://stackoverflow.com/a/7303433/573057 private static String pid() { String name = ManagementFactory.getRuntimeMXBean().getName(); return name.substring(0, name.indexOf('@')); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy