Showing the changes to java/pkg/com/sun/tools/example/debug/gui/ContextManager.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,353 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 1999, Oracle and/or its affiliates. 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. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package com.sun.tools.example.debug.gui; | ||
| 27 | |||
| 28 | import java.io.*; | ||
| 29 | import java.util.*; | ||
| 30 | |||
| 31 | import com.sun.jdi.*; | ||
| 32 | import com.sun.tools.example.debug.event.*; | ||
| 33 | import com.sun.tools.example.debug.bdi.*; | ||
| 34 | |||
| 35 | public class ContextManager { | ||
| 36 | |||
| 37 | private ClassManager classManager; | ||
| 38 | private ExecutionManager runtime; | ||
| 39 | |||
| 40 | private String mainClassName; | ||
| 41 | private String vmArguments; | ||
| 42 | private String commandArguments; | ||
| 43 | private String remotePort; | ||
| 44 | |||
| 45 | private ThreadReference currentThread; | ||
| 46 | |||
| 47 | private boolean verbose; | ||
| 48 | |||
| 49 | private ArrayList<ContextListener> contextListeners = new ArrayList<ContextListener>(); | ||
| 50 | |||
| 51 | public ContextManager(Environment env) { | ||
| 52 | classManager = env.getClassManager(); | ||
| 53 | runtime = env.getExecutionManager(); | ||
| 54 | mainClassName = ""; | ||
| 55 | vmArguments = ""; | ||
| 56 | commandArguments = ""; | ||
| 57 | currentThread = null; | ||
| 58 | |||
| 59 | ContextManagerListener listener = new ContextManagerListener(); | ||
| 60 | runtime.addJDIListener(listener); | ||
| 61 | runtime.addSessionListener(listener); | ||
| 62 | } | ||
| 63 | |||
| 64 | // Program execution defaults. | ||
| 65 | |||
| 66 | //### Should there be change listeners for these? | ||
| 67 | //### They would be needed if we expected a dialog to be | ||
| 68 | //### synchronized with command input while it was open. | ||
| 69 | |||
| 70 | public String getMainClassName() { | ||
| 71 | return mainClassName; | ||
| 72 | } | ||
| 73 | |||
| 74 | public void setMainClassName(String mainClassName) { | ||
| 75 | this.mainClassName = mainClassName; | ||
| 76 | } | ||
| 77 | |||
| 78 | public String getVmArguments() { | ||
| 79 | return processClasspathDefaults(vmArguments); | ||
| 80 | } | ||
| 81 | |||
| 82 | public void setVmArguments(String vmArguments) { | ||
| 83 | this.vmArguments = vmArguments; | ||
| 84 | } | ||
| 85 | |||
| 86 | public String getProgramArguments() { | ||
| 87 | return commandArguments; | ||
| 88 | } | ||
| 89 | |||
| 90 | public void setProgramArguments(String commandArguments) { | ||
| 91 | this.commandArguments = commandArguments; | ||
| 92 | } | ||
| 93 | |||
| 94 | public String getRemotePort() { | ||
| 95 | return remotePort; | ||
| 96 | } | ||
| 97 | |||
| 98 | public void setRemotePort(String remotePort) { | ||
| 99 | this.remotePort = remotePort; | ||
| 100 | |||
| 101 | } | ||
| 102 | |||
| 103 | |||
| 104 | // Miscellaneous debugger session preferences. | ||
| 105 | |||
| 106 | public boolean getVerboseFlag() { | ||
| 107 | return verbose; | ||
| 108 | } | ||
| 109 | |||
| 110 | public void setVerboseFlag(boolean verbose) { | ||
| 111 | this.verbose = verbose; | ||
| 112 | } | ||
| 113 | |||
| 114 | |||
| 115 | // Thread focus. | ||
| 116 | |||
| 117 | public ThreadReference getCurrentThread() { | ||
| 118 | return currentThread; | ||
| 119 | } | ||
| 120 | |||
| 121 | public void setCurrentThread(ThreadReference t) { | ||
| 122 | if (t != currentThread) { | ||
| 123 | currentThread = t; | ||
| 124 | notifyCurrentThreadChanged(t); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | public void setCurrentThreadInvalidate(ThreadReference t) { | ||
| 129 | currentThread = t; | ||
| 130 | notifyCurrentFrameChanged(runtime.threadInfo(t), | ||
| 131 | 0, true); | ||
| 132 | } | ||
| 133 | |||
| 134 | public void invalidateCurrentThread() { | ||
| 135 | notifyCurrentFrameChanged(null, 0, true); | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | // If a view is displaying the current thread, it may | ||
| 140 | // choose to indicate which frame is current in the | ||
| 141 | // sense of the command-line UI. It may also "warp" the | ||
| 142 | // selection to that frame when changed by an 'up' or 'down' | ||
| 143 | // command. Hence, a notifier is provided. | ||
| 144 | |||
| 145 | /****** | ||
| 146 | public int getCurrentFrameIndex() { | ||
| 147 | return getCurrentFrameIndex(currentThreadInfo); | ||
| 148 | } | ||
| 149 | ******/ | ||
| 150 | |||
| 151 | public int getCurrentFrameIndex(ThreadReference t) { | ||
| 152 | return getCurrentFrameIndex(runtime.threadInfo(t)); | ||
| 153 | } | ||
| 154 | |||
| 155 | //### Used in StackTraceTool. | ||
| 156 | public int getCurrentFrameIndex(ThreadInfo tinfo) { | ||
| 157 | if (tinfo == null) { | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | Integer currentFrame = (Integer)tinfo.getUserObject(); | ||
| 161 | if (currentFrame == null) { | ||
| 162 | return 0; | ||
| 163 | } else { | ||
| 164 | return currentFrame.intValue(); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | public int moveCurrentFrameIndex(ThreadReference t, int count) throws VMNotInterruptedException { | ||
| 169 | return setCurrentFrameIndex(t,count, true); | ||
| 170 | } | ||
| 171 | |||
| 172 | public int setCurrentFrameIndex(ThreadReference t, int newIndex) throws VMNotInterruptedException { | ||
| 173 | return setCurrentFrameIndex(t, newIndex, false); | ||
| 174 | } | ||
| 175 | |||
| 176 | public int setCurrentFrameIndex(int newIndex) throws VMNotInterruptedException { | ||
| 177 | if (currentThread == null) { | ||
| 178 | return 0; | ||
| 179 | } else { | ||
| 180 | return setCurrentFrameIndex(currentThread, newIndex, false); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | private int setCurrentFrameIndex(ThreadReference t, int x, boolean relative) throws VMNotInterruptedException { | ||
| 185 | boolean sameThread = t.equals(currentThread); | ||
| 186 | ThreadInfo tinfo = runtime.threadInfo(t); | ||
| 187 | if (tinfo == null) { | ||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | int maxIndex = tinfo.getFrameCount()-1; | ||
| 191 | int oldIndex = getCurrentFrameIndex(tinfo); | ||
| 192 | int newIndex = relative? oldIndex + x : x; | ||
| 193 | if (newIndex > maxIndex) { | ||
| 194 | newIndex = maxIndex; | ||
| 195 | } else if (newIndex < 0) { | ||
| 196 | newIndex = 0; | ||
| 197 | } | ||
| 198 | if (!sameThread || newIndex != oldIndex) { // don't recurse | ||
| 199 | setCurrentFrameIndex(tinfo, newIndex); | ||
| 200 | } | ||
| 201 | return newIndex - oldIndex; | ||
| 202 | } | ||
| 203 | |||
| 204 | private void setCurrentFrameIndex(ThreadInfo tinfo, int index) { | ||
| 205 | tinfo.setUserObject(new Integer(index)); | ||
| 206 | //### In fact, the value may not have changed at this point. | ||
| 207 | //### We need to signal that the user attempted to change it, | ||
| 208 | //### however, so that the selection can be "warped" to the | ||
| 209 | //### current location. | ||
| 210 | notifyCurrentFrameChanged(tinfo.thread(), index); | ||
| 211 | } | ||
| 212 | |||
| 213 | public StackFrame getCurrentFrame() throws VMNotInterruptedException { | ||
| 214 | return getCurrentFrame(runtime.threadInfo(currentThread)); | ||
| 215 | } | ||
| 216 | |||
| 217 | public StackFrame getCurrentFrame(ThreadReference t) throws VMNotInterruptedException { | ||
| 218 | return getCurrentFrame(runtime.threadInfo(t)); | ||
| 219 | } | ||
| 220 | |||
| 221 | public StackFrame getCurrentFrame(ThreadInfo tinfo) throws VMNotInterruptedException { | ||
| 222 | int index = getCurrentFrameIndex(tinfo); | ||
| 223 | try { | ||
| 224 | // It is possible, though unlikely, that the VM was interrupted | ||
| 225 | // before the thread created its Java stack. | ||
| 226 | return tinfo.getFrame(index); | ||
| 227 | } catch (FrameIndexOutOfBoundsException e) { | ||
| 228 | return null; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | public void addContextListener(ContextListener cl) { | ||
| 233 | contextListeners.add(cl); | ||
| 234 | } | ||
| 235 | |||
| 236 | public void removeContextListener(ContextListener cl) { | ||
| 237 | contextListeners.remove(cl); | ||
| 238 | } | ||
| 239 | |||
| 240 | //### These notifiers are fired only in response to USER-INITIATED changes | ||
| 241 | //### to the current thread and current frame. When the current thread is set automatically | ||
| 242 | //### after a breakpoint hit or step completion, no event is generated. Instead, | ||
| 243 | //### interested parties are expected to listen for the BreakpointHit and StepCompleted | ||
| 244 | //### events. This convention is unclean, and I believe that it reflects a defect in | ||
| 245 | //### in the current architecture. Unfortunately, however, we cannot guarantee the | ||
| 246 | //### order in which various listeners receive a given event, and the handlers for | ||
| 247 | //### the very same events that cause automatic changes to the current thread may also | ||
| 248 | //### need to know the current thread. | ||
| 249 | |||
| 250 | private void notifyCurrentThreadChanged(ThreadReference t) { | ||
| 251 | ThreadInfo tinfo = null; | ||
| 252 | int index = 0; | ||
| 253 | if (t != null) { | ||
| 254 | tinfo = runtime.threadInfo(t); | ||
| 255 | index = getCurrentFrameIndex(tinfo); | ||
| 256 | } | ||
| 257 | notifyCurrentFrameChanged(tinfo, index, false); | ||
| 258 | } | ||
| 259 | |||
| 260 | private void notifyCurrentFrameChanged(ThreadReference t, int index) { | ||
| 261 | notifyCurrentFrameChanged(runtime.threadInfo(t), | ||
| 262 | index, false); | ||
| 263 | } | ||
| 264 | |||
| 265 | private void notifyCurrentFrameChanged(ThreadInfo tinfo, int index, | ||
| 266 | boolean invalidate) { | ||
| 267 | ArrayList<ContextListener> l = new ArrayList<ContextListener>(contextListeners); | ||
| 268 | CurrentFrameChangedEvent evt = | ||
| 269 | new CurrentFrameChangedEvent(this, tinfo, index, invalidate); | ||
| 270 | for (int i = 0; i < l.size(); i++) { | ||
| 271 | l.get(i).currentFrameChanged(evt); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | private class ContextManagerListener extends JDIAdapter | ||
| 276 | implements SessionListener, JDIListener { | ||
| 277 | |||
| 278 | // SessionListener | ||
| 279 | |||
| 280 | @Override | ||
| 281 | public void sessionStart(EventObject e) { | ||
| 282 | invalidateCurrentThread(); | ||
| 283 | } | ||
| 284 | |||
| 285 | @Override | ||
| 286 | public void sessionInterrupt(EventObject e) { | ||
| 287 | setCurrentThreadInvalidate(currentThread); | ||
| 288 | } | ||
| 289 | |||
| 290 | @Override | ||
| 291 | public void sessionContinue(EventObject e) { | ||
| 292 | invalidateCurrentThread(); | ||
| 293 | } | ||
| 294 | |||
| 295 | // JDIListener | ||
| 296 | |||
| 297 | @Override | ||
| 298 | public void locationTrigger(LocationTriggerEventSet e) { | ||
| 299 | setCurrentThreadInvalidate(e.getThread()); | ||
| 300 | } | ||
| 301 | |||
| 302 | @Override | ||
| 303 | public void exception(ExceptionEventSet e) { | ||
| 304 | setCurrentThreadInvalidate(e.getThread()); | ||
| 305 | } | ||
| 306 | |||
| 307 | @Override | ||
| 308 | public void vmDisconnect(VMDisconnectEventSet e) { | ||
| 309 | invalidateCurrentThread(); | ||
| 310 | } | ||
| 311 | |||
| 312 | } | ||
| 313 | |||
| 314 | |||
| 315 | /** | ||
| 316 | * Add a -classpath argument to the arguments passed to the exec'ed | ||
| 317 | * VM with the contents of CLASSPATH environment variable, | ||
| 318 | * if -classpath was not already specified. | ||
| 319 | * | ||
| 320 | * @param javaArgs the arguments to the VM being exec'd that | ||
| 321 | * potentially has a user specified -classpath argument. | ||
| 322 | * @return a javaArgs whose -classpath option has been added | ||
| 323 | */ | ||
| 324 | |||
| 325 | private String processClasspathDefaults(String javaArgs) { | ||
| 326 | if (javaArgs.indexOf("-classpath ") == -1) { | ||
| 327 | StringBuffer munged = new StringBuffer(javaArgs); | ||
| 328 | SearchPath classpath = classManager.getClassPath(); | ||
| 329 | if (classpath.isEmpty()) { | ||
| 330 | String envcp = System.getProperty("env.class.path"); | ||
| 331 | if ((envcp != null) && (envcp.length() > 0)) { | ||
| 332 | munged.append(" -classpath " + envcp); | ||
| 333 | } | ||
| 334 | } else { | ||
| 335 | munged.append(" -classpath " + classpath.asString()); | ||
| 336 | } | ||
| 337 | return munged.toString(); | ||
| 338 | } else { | ||
| 339 | return javaArgs; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | private String appendPath(String path1, String path2) { | ||
| 344 | if (path1 == null || path1.length() == 0) { | ||
| 345 | return path2 == null ? "." : path2; | ||
| 346 | } else if (path2 == null || path2.length() == 0) { | ||
| 347 | return path1; | ||
| 348 | } else { | ||
| 349 | return path1 + File.pathSeparator + path2; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | } | ||