/**************************************************************************************
* Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved. *
* http://aspectwerkz.codehaus.org *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package org.codehaus.aspectwerkz.hook;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.Bootstrap;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import java.util.Map;
import java.util.Iterator;
import java.io.IOException;
/**
* Isolation of JDWP dependancies to Plug online mode in a running / remote VM.
* See Plug.
*
* @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
*/
public class JDWPPlug {
/**
* transport jdwp option
*/
private final static String TRANSPORT_JDWP = "transport";
/**
* address jdwp option
*/
private final static String ADDRESS_JDWP = "address";
/**
* Connects to a remote JVM using the jdwp options specified in jdwp
*
* @param jdwp
* @return VirtualMachine or null if failure
* @throws Exception
*/
private VirtualMachine connect(Map jdwp) throws Exception {
String transport = (String) jdwp.get(TRANSPORT_JDWP);
String address = (String) jdwp.get(ADDRESS_JDWP);
String name = null;
if ("dt_socket".equals(transport)) {
name = "com.sun.jdi.SocketAttach";
} else if ("dt_shmem".equals(transport)) {
name = "com.sun.jdi.SharedMemoryAttach";
}
AttachingConnector connector = null;
for (Iterator i = Bootstrap.virtualMachineManager().attachingConnectors().iterator(); i.hasNext();) {
AttachingConnector aConnector = (AttachingConnector) i.next();
if (aConnector.name().equals(name)) {
connector = aConnector;
break;
}
}
if (connector == null) {
throw new Exception("no AttachingConnector for transport: " + transport);
}
Map args = connector.defaultArguments();
if ("dt_socket".equals(transport)) {
((Connector.Argument) args.get("port")).setValue(address);
} else if ("dt_shmem".equals(transport)) {
((Connector.Argument) args.get("name")).setValue(address);
}
try {
VirtualMachine vm = connector.attach(args);
return vm;
} catch (IllegalConnectorArgumentsException e) {
System.err.println("failed to attach to VM (" + transport + ", " + address + "):");
e.printStackTrace();
for (Iterator i = e.argumentNames().iterator(); i.hasNext();) {
System.err.println("wrong or missing argument - " + i.next());
}
return null;
} catch (IOException e) {
System.err.println("failed to attach to VM (" + transport + ", " + address + "):");
e.printStackTrace();
return null;
}
}
/**
* Resume the remote JVM, without hotswapping classes
*
* @param jdwp
* @throws Exception
*/
public void resume(Map jdwp) throws Exception {
VirtualMachine vm = connect(jdwp);
if (vm != null) {
vm.resume();
vm.dispose();
}
}
/**
* Prints information about the remote JVM and resume
*
* @param jdwp
* @throws Exception
*/
public void info(Map jdwp) throws Exception {
VirtualMachine vm = connect(jdwp);
if (vm != null) {
System.out.println("java.vm.name = " + vm.name());
System.out.println("java.version = " + vm.version());
System.out.println(vm.description());
vm.resume();
vm.dispose();
}
}
/**
* Hotswaps the java.lang.ClassLoader of the remote JVM and resume
*
* @param jdwp
* @throws Exception
*/
public void hotswap(Map jdwp) throws Exception {
// @todo check it works at runtime not suspended
VirtualMachine vm = ClassLoaderPatcher.hotswapClassLoader(
System.getProperty(
ProcessStarter.CL_PRE_PROCESSOR_CLASSNAME_PROPERTY,
org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl.class.getName()
), (String) jdwp
.get(TRANSPORT_JDWP), (String) jdwp.get(ADDRESS_JDWP)
);
if (vm != null) {
vm.resume();
vm.dispose();
}
}
}