1 /* 2 * Copyright 2012 SAP AG. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test FieldMonitor.java 26 * @bug 7158988 27 * @key regression 28 * @summary verify jvm does not crash while debugging 29 * @run compile TestPostFieldModification.java 30 * @run main/othervm FieldMonitor 31 * @author axel.siebenborn@sap.com 32 */ 33 import java.io.BufferedReader; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.InputStreamReader; 37 import java.util.Iterator; 38 import java.util.List; 39 import java.util.Map; 40 41 import com.sun.jdi.Bootstrap; 42 import com.sun.jdi.Field; 43 import com.sun.jdi.ReferenceType; 44 import com.sun.jdi.VirtualMachine; 45 import com.sun.jdi.connect.Connector; 46 import com.sun.jdi.connect.IllegalConnectorArgumentsException; 47 import com.sun.jdi.connect.LaunchingConnector; 48 import com.sun.jdi.connect.VMStartException; 49 import com.sun.jdi.event.ClassPrepareEvent; 50 import com.sun.jdi.event.Event; 51 import com.sun.jdi.event.EventQueue; 52 import com.sun.jdi.event.EventSet; 53 import com.sun.jdi.event.ModificationWatchpointEvent; 54 import com.sun.jdi.event.VMDeathEvent; 55 import com.sun.jdi.event.VMDisconnectEvent; 56 import com.sun.jdi.request.ClassPrepareRequest; 57 import com.sun.jdi.request.EventRequest; 58 import com.sun.jdi.request.EventRequestManager; 59 import com.sun.jdi.request.ModificationWatchpointRequest; 60 61 public class FieldMonitor { 62 63 public static final String CLASS_NAME = "TestPostFieldModification"; 64 public static final String FIELD_NAME = "value"; 65 public static final String ARGUMENTS = "-Xshare:off -XX:+PrintGC"; 66 67 public static void main(String[] args) 68 throws IOException, InterruptedException { 69 70 //VirtualMachine vm = launchTarget(sb.toString()); 71 VirtualMachine vm = launchTarget(CLASS_NAME); 72 73 System.out.println("Vm launched"); 74 75 // watch for loaded classes 76 addClassWatch(vm); 77 78 // process events 79 EventQueue eventQueue = vm.eventQueue(); 80 // resume the vm 81 82 Process process = vm.process(); 83 84 85 // Copy target's output and error to our output and error. 86 Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); 87 Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); 88 89 errThread.start(); 90 outThread.start(); 91 92 boolean connected = true; 93 while (connected) { 94 EventSet eventSet = eventQueue.remove(); 95 for (Event event : eventSet) { 96 if (event instanceof VMDeathEvent 97 || event instanceof VMDisconnectEvent) { 98 // exit 99 connected = false; 100 } else if (event instanceof ClassPrepareEvent) { 101 // watch field on loaded class 102 System.out.println("ClassPrepareEvent"); 103 ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; 104 ReferenceType refType = classPrepEvent 105 .referenceType(); 106 addFieldWatch(vm, refType); 107 } else if (event instanceof ModificationWatchpointEvent) { 108 System.out.println("sleep for 500 ms"); 109 Thread.sleep(500); 110 System.out.println("resume..."); 111 112 ModificationWatchpointEvent modEvent = (ModificationWatchpointEvent) event; 113 System.out.println("old=" 114 + modEvent.valueCurrent()); 115 System.out.println("new=" + modEvent.valueToBe()); 116 System.out.println(); 117 } 118 } 119 eventSet.resume(); 120 } 121 // Shutdown begins when event thread terminates 122 try { 123 errThread.join(); // Make sure output is forwarded 124 outThread.join(); 125 } catch (InterruptedException exc) { 126 // we don't interrupt 127 } 128 } 129 130 /** 131 * Find a com.sun.jdi.CommandLineLaunch connector 132 */ 133 static LaunchingConnector findLaunchingConnector() { 134 List <Connector> connectors = Bootstrap.virtualMachineManager().allConnectors(); 135 Iterator <Connector> iter = connectors.iterator(); 136 while (iter.hasNext()) { 137 Connector connector = iter.next(); 138 if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { 139 return (LaunchingConnector)connector; 140 } 141 } 142 throw new Error("No launching connector"); 143 } 144 /** 145 * Return the launching connector's arguments. 146 */ 147 static Map <String,Connector.Argument> connectorArguments(LaunchingConnector connector, String mainArgs) { 148 Map<String,Connector.Argument> arguments = connector.defaultArguments(); 149 for (String key : arguments.keySet()) { 150 System.out.println(key); 151 } 152 153 Connector.Argument mainArg = (Connector.Argument)arguments.get("main"); 154 if (mainArg == null) { 155 throw new Error("Bad launching connector"); 156 } 157 mainArg.setValue(mainArgs); 158 159 Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); 160 if (optionsArg == null) { 161 throw new Error("Bad launching connector"); 162 } 163 optionsArg.setValue(ARGUMENTS); 164 return arguments; 165 } 166 167 static VirtualMachine launchTarget(String mainArgs) { 168 LaunchingConnector connector = findLaunchingConnector(); 169 Map arguments = connectorArguments(connector, mainArgs); 170 try { 171 return (VirtualMachine) connector.launch(arguments); 172 } catch (IOException exc) { 173 throw new Error("Unable to launch target VM: " + exc); 174 } catch (IllegalConnectorArgumentsException exc) { 175 throw new Error("Internal error: " + exc); 176 } catch (VMStartException exc) { 177 throw new Error("Target VM failed to initialize: " + 178 exc.getMessage()); 179 } 180 } 181 182 183 private static void addClassWatch(VirtualMachine vm) { 184 EventRequestManager erm = vm.eventRequestManager(); 185 ClassPrepareRequest classPrepareRequest = erm 186 .createClassPrepareRequest(); 187 classPrepareRequest.addClassFilter(CLASS_NAME); 188 classPrepareRequest.setEnabled(true); 189 } 190 191 192 private static void addFieldWatch(VirtualMachine vm, 193 ReferenceType refType) { 194 EventRequestManager erm = vm.eventRequestManager(); 195 Field field = refType.fieldByName(FIELD_NAME); 196 ModificationWatchpointRequest modificationWatchpointRequest = erm 197 .createModificationWatchpointRequest(field); 198 modificationWatchpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); 199 modificationWatchpointRequest.setEnabled(true); 200 } 201 } 202 203 class StreamRedirectThread extends Thread { 204 205 private final BufferedReader in; 206 207 private static final int BUFFER_SIZE = 2048; 208 209 /** 210 * Set up for copy. 211 * @param name Name of the thread 212 * @param in Stream to copy from 213 * @param out Stream to copy to 214 */ 215 StreamRedirectThread(String name, InputStream in) { 216 super(name); 217 this.in = new BufferedReader(new InputStreamReader(in)); 218 } 219 220 /** 221 * Copy. 222 */ 223 public void run() { 224 try { 225 String line; 226 while ((line = in.readLine ()) != null) { 227 System.out.println ("testvm: " + line); 228 } 229 System.out.flush(); 230 } catch(IOException exc) { 231 System.err.println("Child I/O Transfer - " + exc); 232 } 233 } 234 }