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