/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.util;
//import com.sun.jdi.*;
//import com.sun.jdi.connect.*;
//import com.sun.jdi.event.*;
//import com.sun.jdi.request.*;
import java.io.*;
import java.util.*;
class Trigger {
void doSwap() {}
}
/**
* A utility class for dynamically reloading a class by
* the Java Platform Debugger Architecture (JPDA), or <it>HotSwap</code>.
* It works only with JDK 1.4 and later.
*
* <p><b>Note:</b> The new definition of the reloaded class must declare
* the same set of methods and fields as the original definition. The
* schema change between the original and new definitions is not allowed
* by the JPDA.
*
* <p>To use this class, the JVM must be launched with the following
* command line options:
*
* <ul>
* <p>For Java 1.4,<br>
* <pre>java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000</pre>
* <p>For Java 5,<br>
* <pre>java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000</pre>
* </ul>
*
* <p>Note that 8000 is the port number used by <code>HotSwapper</code>.
* Any port number can be specified. Since <code>HotSwapper</code> does not
* launch another JVM for running a target application, this port number
* is used only for inter-thread communication.
*
* <p>Furthermore, <code>JAVA_HOME/lib/tools.jar</code> must be included
* in the class path.
*
* <p>Using <code>HotSwapper</code> is easy. See the following example:
*
* <ul><pre>
* CtClass clazz = ...
* byte[] classFile = clazz.toBytecode();
* HotSwapper hs = new HostSwapper(8000); // 8000 is a port number.
* hs.reload("Test", classFile);
* </pre></ul>
*
* <p><code>reload()</code>
* first unload the <code>Test</code> class and load a new version of
* the <code>Test</code> class.
* <code>classFile</code> is a byte array containing the new contents of
* the class file for the <code>Test</code> class. The developers can
* repatedly call <code>reload()</code> on the same <code>HotSwapper</code>
* object so that they can reload a number of classes.
*
* @since 3.1
*/
public class HotSwapper {
//private VirtualMachine jvm;
//private MethodEntryRequest request;
//private Map newClassFiles;
//private Trigger trigger;
//private static final String HOST_NAME = "localhost";
//private static final String TRIGGER_NAME = Trigger.class.getName();
/**
* Connects to the JVM.
*
* @param port the port number used for the connection to the JVM.
*/
public HotSwapper(int port)
throws IOException//, IllegalConnectorArgumentsException
{
//this(Integer.toString(port));
}
/**
* Connects to the JVM.
*
* @param port the port number used for the connection to the JVM.
*/
public HotSwapper(String port)
throws IOException//, IllegalConnectorArgumentsException
{
// jvm = null;
// request = null;
// newClassFiles = null;
// trigger = new Trigger();
// AttachingConnector connector
// = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
//
// Map arguments = connector.defaultArguments();
// ((Connector.Argument)arguments.get("hostname")).setValue(HOST_NAME);
// ((Connector.Argument)arguments.get("port")).setValue(port);
// jvm = connector.attach(arguments);
// EventRequestManager manager = jvm.eventRequestManager();
// request = methodEntryRequests(manager, TRIGGER_NAME);
}
// private Connector findConnector(String connector) throws IOException {
// List connectors = Bootstrap.virtualMachineManager().allConnectors();
// Iterator iter = connectors.iterator();
// while (iter.hasNext()) {
// Connector con = (Connector)iter.next();
// if (con.name().equals(connector)) {
// return con;
// }
// }
//
// throw new IOException("Not found: " + connector);
// }
// private static MethodEntryRequest methodEntryRequests(
// EventRequestManager manager,
// String classpattern) {
// MethodEntryRequest mereq = manager.createMethodEntryRequest();
// mereq.addClassFilter(classpattern);
// mereq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
// return mereq;
// }
/* Stops triggering a hotswapper when reload() is called.
*/
// private void deleteEventRequest(EventRequestManager manager,
// MethodEntryRequest request) {
// manager.deleteEventRequest(request);
// }
/**
* Reloads a class.
*
* @param className the fully-qualified class name.
* @param classFile the contents of the class file.
*/
public void reload(String className, byte[] classFile) {
// ReferenceType classtype = toRefType(className);
// Map map = new HashMap();
// map.put(classtype, classFile);
// reload2(map, className);
}
/**
* Reloads a class.
*
* @param classFiles a map between fully-qualified class names
* and class files. The type of the class names
* is <code>String</code> and the type of the
* class files is <code>byte[]</code>.
*/
public void reload(Map<?, ?> classFiles) {
// Set set = classFiles.entrySet();
// Iterator it = set.iterator();
// Map map = new HashMap();
// String className = null;
// while (it.hasNext()) {
// Map.Entry e = (Map.Entry)it.next();
// className = (String)e.getKey();
// map.put(toRefType(className), e.getValue());
// }
//
// if (className != null)
// reload2(map, className + " etc.");
}
// private ReferenceType toRefType(String className) {
// List list = jvm.classesByName(className);
// if (list == null || list.isEmpty())
// throw new RuntimeException("no such class: " + className);
// else
// return (ReferenceType)list.get(0);
// }
// private void reload2(Map map, String msg) {
// synchronized (trigger) {
// startDaemon();
// newClassFiles = map;
// request.enable();
// trigger.doSwap();
// request.disable();
// Map ncf = newClassFiles;
// if (ncf != null) {
// newClassFiles = null;
// throw new RuntimeException("failed to reload: " + msg);
// }
// }
// }
// private void startDaemon() {
// new Thread() {
// private void errorMsg(Throwable e) {
// System.err.print("Exception in thread \"HotSwap\" ");
// e.printStackTrace(System.err);
// }
//
// public void run() {
// EventSet events = null;
// try {
// events = waitEvent();
// EventIterator iter = events.eventIterator();
// while (iter.hasNext()) {
// Event event = iter.nextEvent();
// if (event instanceof MethodEntryEvent) {
// hotswap();
// break;
// }
// }
// }
// catch (Throwable e) {
// errorMsg(e);
// }
// try {
// if (events != null)
// events.resume();
// }
// catch (Throwable e) {
// errorMsg(e);
// }
// }
// }.start();
// }
// EventSet waitEvent() throws InterruptedException {
// EventQueue queue = jvm.eventQueue();
// return queue.remove();
// }
//
// void hotswap() {
// Map map = newClassFiles;
// jvm.redefineClasses(map);
// newClassFiles = null;
// }
}