1 8 package org.codehaus.aspectwerkz.hook; 9 10 import com.sun.jdi.Bootstrap; 11 import com.sun.jdi.ReferenceType; 12 import com.sun.jdi.VirtualMachine; 13 import com.sun.jdi.connect.AttachingConnector; 14 import com.sun.jdi.connect.Connector; 15 import com.sun.jdi.connect.IllegalConnectorArgumentsException; 16 17 import java.io.BufferedOutputStream ; 18 import java.io.ByteArrayOutputStream ; 19 import java.io.DataOutputStream ; 20 import java.io.File ; 21 import java.io.FileOutputStream ; 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.lang.reflect.Method ; 26 import java.net.ConnectException ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 32 37 public class ClassLoaderPatcher { 38 41 public static byte[] inputStreamToByteArray(InputStream is) throws IOException { 42 ByteArrayOutputStream os = new ByteArrayOutputStream (); 43 for (int b = is.read(); b != -1; b = is.read()) { 44 os.write(b); 45 } 46 return os.toByteArray(); 47 } 48 49 52 static byte[] getPatchedClassLoader(String preProcessorName) { 53 byte[] abyte = null; 54 InputStream is = null; 55 try { 56 is = ClassLoader.getSystemClassLoader().getParent().getResourceAsStream("java/lang/ClassLoader.class"); 57 abyte = inputStreamToByteArray(is); 58 } catch (IOException e) { 59 throw new Error ("failed to read java.lang.ClassLoader: " + e.toString()); 60 } finally { 61 try { 62 is.close(); 63 } catch (Exception e) { 64 ; 65 } 66 } 67 if (preProcessorName != null) { 68 try { 69 ClassLoaderPreProcessor clpi = (ClassLoaderPreProcessor) Class.forName(preProcessorName).newInstance(); 70 abyte = clpi.preProcess(abyte); 71 } catch (Exception e) { 72 System.err.println("failed to instrument java.lang.ClassLoader: preprocessor not found"); 73 e.printStackTrace(); 74 } 75 } 76 return abyte; 77 } 78 79 82 private static void writeClass(String className, byte[] bytes, String dir) { 83 String filename = dir + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; 84 int pos = filename.lastIndexOf(File.separatorChar); 85 if (pos > 0) { 86 String finalDir = filename.substring(0, pos); 87 (new File (finalDir)).mkdirs(); 88 } 89 try { 90 DataOutputStream out = new DataOutputStream (new BufferedOutputStream (new FileOutputStream (filename))); 91 out.write(bytes); 92 out.close(); 93 } catch (IOException e) { 94 System.err.println("failed to write " + className + " in " + dir); 95 e.printStackTrace(); 96 } 97 } 98 99 102 private static void redefineClass(VirtualMachine vm, String className, byte[] bytes) { 103 try { 105 Method canM = VirtualMachine.class.getMethod("canRedefineClasses", new Class []{}); 106 if (((Boolean ) canM.invoke(vm, new Object []{})).equals(Boolean.FALSE)) { 107 throw new Error ("target JVM cannot redefine classes, please force the use of -Xbootclasspath"); 108 } 109 List classList = vm.classesByName(className); 110 if (classList.size() == 0) { 111 throw new Error ("Fatal error: Can't find class " + className); 112 } 113 ReferenceType rt = (ReferenceType) classList.get(0); 114 Map map = new HashMap (); 115 map.put(rt, bytes); 116 Method doM = VirtualMachine.class.getMethod( 117 "redefineClasses", new Class []{ 118 Map .class 119 } 120 ); 121 doM.invoke( 122 vm, new Object []{ 123 map 124 } 125 ); 126 } catch (NoSuchMethodException e) { 127 throw new Error ("target JVM cannot redefine classes, please force the use of -Xbootclasspath"); 129 } catch (InvocationTargetException e) { 130 System.err.println("failed to HotSwap " + className + ':'); 132 e.getTargetException().printStackTrace(); 133 throw new Error ("try to force force the use of -Xbootclasspath"); 134 } catch (IllegalAccessException e) { 135 System.err.println("failed to HotSwap " + className + ':'); 137 e.printStackTrace(); 138 throw new Error ("try to force force the use of -Xbootclasspath"); 139 } 140 } 141 142 145 public static void patchClassLoader(String preProcessorName, String dir) { 146 byte[] cl = getPatchedClassLoader(preProcessorName); 147 writeClass("java.lang.ClassLoader", cl, dir); 148 } 149 150 154 public static VirtualMachine hotswapClassLoader(String preProcessorName, String transport, String address) { 155 return hotswapClassLoader(preProcessorName, transport, address, 0); 156 } 157 158 162 public static VirtualMachine hotswapClassLoader(String preProcessorName, 163 String transport, 164 String address, 165 int secondsToWait) { 166 String name = null; 167 if ("dt_socket".equals(transport)) { 168 name = "com.sun.jdi.SocketAttach"; 169 } else if ("dt_shmem".equals(transport)) { 170 name = "com.sun.jdi.SharedMemoryAttach"; 171 } 172 AttachingConnector connector = null; 173 for (Iterator i = Bootstrap.virtualMachineManager().attachingConnectors().iterator(); i.hasNext();) { 174 AttachingConnector aConnector = (AttachingConnector) i.next(); 175 if (aConnector.name().equals(name)) { 176 connector = aConnector; 177 break; 178 } 179 } 180 if (connector == null) { 181 throw new Error ("no AttachingConnector for transport: " + transport); 182 } 183 Map args = connector.defaultArguments(); 184 if ("dt_socket".equals(transport)) { 185 ((Connector.Argument) args.get("port")).setValue(address); 186 } else if ("dt_shmem".equals(transport)) { 187 ((Connector.Argument) args.get("name")).setValue(address); 188 } 189 try { 190 if (secondsToWait > 0) { 191 try { 192 Thread.sleep(1000 * secondsToWait); 193 } catch (Exception e) { 194 ; 195 } 196 } 197 198 VirtualMachine vm = null; 202 ConnectException vmConnectionRefused = new ConnectException ("should not appear as is"); 203 for (int retry = 0; retry < 10; retry++) { 204 try { 205 vm = connector.attach(args); 206 break; 207 } catch (ConnectException ce) { 208 vmConnectionRefused = ce; 209 try { 210 Thread.sleep(500); 211 } catch (Throwable t) { 212 ; 213 } 214 } 215 } 216 if (vm == null) { 217 throw vmConnectionRefused; 218 } 219 redefineClass(vm, "java.lang.ClassLoader", getPatchedClassLoader(preProcessorName)); 220 return vm; 221 } catch (IllegalConnectorArgumentsException e) { 222 System.err.println("failed to attach to VM (" + transport + ", " + address + "):"); 223 e.printStackTrace(); 224 for (Iterator i = e.argumentNames().iterator(); i.hasNext();) { 225 System.err.println("wrong or missing argument - " + i.next()); 226 } 227 return null; 228 } catch (IOException e) { 229 System.err.println("failed to attach to VM (" + transport + ", " + address + "):"); 230 e.printStackTrace(); 231 return null; 232 } 233 } 234 } | Popular Tags |