169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.util;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport com.sun.jdi.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport com.sun.jdi.connect.*;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport com.sun.jdi.event.*;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport com.sun.jdi.request.*;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.*;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.*;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalclass Trigger {
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    void doSwap() {}
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A utility class for dynamically reloading a class by
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the Java Platform Debugger Architecture (JPDA), or <it>HotSwap</code>.
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It works only with JDK 1.4 and later.
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p><b>Note:</b> The new definition of the reloaded class must declare
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the same set of methods and fields as the original definition.  The
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * schema change between the original and new definitions is not allowed
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * by the JPDA.
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To use this class, the JVM must be launched with the following
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * command line options:
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul>
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>For Java 1.4,<br>
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <pre>java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000</pre>
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>For Java 5,<br>
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <pre>java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000</pre>
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </ul>
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Note that 8000 is the port number used by <code>HotSwapper</code>.
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Any port number can be specified.  Since <code>HotSwapper</code> does not
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * launch another JVM for running a target application, this port number
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is used only for inter-thread communication.
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Furthermore, <code>JAVA_HOME/lib/tools.jar</code> must be included
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * in the class path.
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Using <code>HotSwapper</code> is easy.  See the following example:
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * CtClass clazz = ...
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * byte[] classFile = clazz.toBytecode();
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * HotSwapper hs = new HostSwapper(8000);  // 8000 is a port number.
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * hs.reload("Test", classFile);
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul>
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p><code>reload()</code>
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * first unload the <code>Test</code> class and load a new version of
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the <code>Test</code> class.
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>classFile</code> is a byte array containing the new contents of
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the class file for the <code>Test</code> class.  The developers can
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * repatedly call <code>reload()</code> on the same <code>HotSwapper</code>
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * object so that they can reload a number of classes.
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @since 3.1
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class HotSwapper {
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private VirtualMachine jvm;
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private MethodEntryRequest request;
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map newClassFiles;
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Trigger trigger;
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String HOST_NAME = "localhost";
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final String TRIGGER_NAME = Trigger.class.getName();
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Connects to the JVM.
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port	the port number used for the connection to the JVM.
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public HotSwapper(int port)
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, IllegalConnectorArgumentsException
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(Integer.toString(port));
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Connects to the JVM.
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port	the port number used for the connection to the JVM.
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public HotSwapper(String port)
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, IllegalConnectorArgumentsException
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        jvm = null;
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        request = null;
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        newClassFiles = null;
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        trigger = new Trigger();
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        AttachingConnector connector
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map arguments = connector.defaultArguments();
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ((Connector.Argument)arguments.get("hostname")).setValue(HOST_NAME);
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ((Connector.Argument)arguments.get("port")).setValue(port);
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        jvm = connector.attach(arguments);
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        EventRequestManager manager = jvm.eventRequestManager();
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        request = methodEntryRequests(manager, TRIGGER_NAME);
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Connector findConnector(String connector) throws IOException {
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        List connectors = Bootstrap.virtualMachineManager().allConnectors();
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Iterator iter = connectors.iterator();
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (iter.hasNext()) {
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Connector con = (Connector)iter.next();
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (con.name().equals(connector)) {
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return con;
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new IOException("Not found: " + connector);
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static MethodEntryRequest methodEntryRequests(
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                EventRequestManager manager,
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                String classpattern) {
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MethodEntryRequest mereq = manager.createMethodEntryRequest();
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        mereq.addClassFilter(classpattern);
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        mereq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return mereq;
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* Stops triggering a hotswapper when reload() is called.
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void deleteEventRequest(EventRequestManager manager,
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                    MethodEntryRequest request) {
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        manager.deleteEventRequest(request);
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Reloads a class.
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param className		the fully-qualified class name.
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param classFile		the contents of the class file.
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void reload(String className, byte[] classFile) {
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ReferenceType classtype = toRefType(className);
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map = new HashMap();
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        map.put(classtype, classFile);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        reload2(map, className);
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Reloads a class.
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param classFiles	a map between fully-qualified class names
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *				and class files.  The type of the class names
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *				is <code>String</code> and the type of the
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *				class files is <code>byte[]</code>.
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void reload(Map classFiles) {
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Set set = classFiles.entrySet();
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Iterator it = set.iterator();
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map = new HashMap();
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String className = null;
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (it.hasNext()) {
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map.Entry e = (Map.Entry)it.next();
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            className = (String)e.getKey();
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            map.put(toRefType(className), e.getValue());
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (className != null)
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            reload2(map, className + " etc.");
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ReferenceType toRefType(String className) {
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        List list = jvm.classesByName(className);
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (list == null || list.isEmpty())
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RuntimeException("no such class: " + className);
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return (ReferenceType)list.get(0);
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void reload2(Map map, String msg) {
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        synchronized (trigger) {
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            startDaemon();
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            newClassFiles = map;
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            request.enable();
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            trigger.doSwap();
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            request.disable();
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Map ncf = newClassFiles;
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (ncf != null) {
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                newClassFiles = null;
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new RuntimeException("failed to reload: " + msg);
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void startDaemon() {
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        new Thread() {
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            private void errorMsg(Throwable e) {
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                System.err.print("Exception in thread \"HotSwap\" ");
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                e.printStackTrace(System.err);
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            public void run() {
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                EventSet events = null;
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                try {
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    events = waitEvent();
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    EventIterator iter = events.eventIterator();
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    while (iter.hasNext()) {
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        Event event = iter.nextEvent();
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        if (event instanceof MethodEntryEvent) {
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            hotswap();
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            break;
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        }
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    }
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                catch (Throwable e) {
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    errorMsg(e);
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                try {
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (events != null)
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        events.resume();
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                catch (Throwable e) {
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    errorMsg(e);
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }.start();
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    EventSet waitEvent() throws InterruptedException {
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        EventQueue queue = jvm.eventQueue();
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return queue.remove();
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    void hotswap() {
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map = newClassFiles;
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        jvm.redefineClasses(map);
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        newClassFiles = null;
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
253