blob: 823c6c52766f4fb51ac26664b5216620208bdee8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-1999 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.tools.example.debug.gui;
27
28import java.io.*;
29import java.util.*;
30
31import com.sun.jdi.*;
32import com.sun.tools.example.debug.event.*;
33import com.sun.tools.example.debug.bdi.*;
34
35public 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 Vector<ContextListener> contextListeners = new Vector<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 Vector l = (Vector)contextListeners.clone();
268 CurrentFrameChangedEvent evt =
269 new CurrentFrameChangedEvent(this, tinfo, index, invalidate);
270 for (int i = 0; i < l.size(); i++) {
271 ((ContextListener)l.elementAt(i)).currentFrameChanged(evt);
272 }
273 }
274
275 private class ContextManagerListener extends JDIAdapter
276 implements SessionListener, JDIListener {
277
278 // SessionListener
279
280 public void sessionStart(EventObject e) {
281 invalidateCurrentThread();
282 }
283
284 public void sessionInterrupt(EventObject e) {
285 setCurrentThreadInvalidate(currentThread);
286 }
287
288 public void sessionContinue(EventObject e) {
289 invalidateCurrentThread();
290 }
291
292 // JDIListener
293
294 public void locationTrigger(LocationTriggerEventSet e) {
295 setCurrentThreadInvalidate(e.getThread());
296 }
297
298 public void exception(ExceptionEventSet e) {
299 setCurrentThreadInvalidate(e.getThread());
300 }
301
302 public void vmDisconnect(VMDisconnectEventSet e) {
303 invalidateCurrentThread();
304 }
305
306 }
307
308
309 /**
310 * Add a -classpath argument to the arguments passed to the exec'ed
311 * VM with the contents of CLASSPATH environment variable,
312 * if -classpath was not already specified.
313 *
314 * @param javaArgs the arguments to the VM being exec'd that
315 * potentially has a user specified -classpath argument.
316 * @return a javaArgs whose -classpath option has been added
317 */
318
319 private String processClasspathDefaults(String javaArgs) {
320 if (javaArgs.indexOf("-classpath ") == -1) {
321 StringBuffer munged = new StringBuffer(javaArgs);
322 SearchPath classpath = classManager.getClassPath();
323 if (classpath.isEmpty()) {
324 String envcp = System.getProperty("env.class.path");
325 if ((envcp != null) && (envcp.length() > 0)) {
326 munged.append(" -classpath " + envcp);
327 }
328 } else {
329 munged.append(" -classpath " + classpath.asString());
330 }
331 return munged.toString();
332 } else {
333 return javaArgs;
334 }
335 }
336
337 private String appendPath(String path1, String path2) {
338 if (path1 == null || path1.length() == 0) {
339 return path2 == null ? "." : path2;
340 } else if (path2 == null || path2.length() == 0) {
341 return path1;
342 } else {
343 return path1 + File.pathSeparator + path2;
344 }
345 }
346
347}