KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > example > debug > tty > VMConnection


1 /*
2  * @(#)VMConnection.java 1.46 05/11/17
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 /*
8  * Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
11  * modify and redistribute this software in source and binary code form,
12  * provided that i) this copyright notice and license appear on all copies of
13  * the software; and ii) Licensee does not utilize the software in a manner
14  * which is disparaging to Sun.
15  *
16  * This software is provided "AS IS," without a warranty of any kind. ALL
17  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
18  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
19  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
20  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
21  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
22  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
23  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
24  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
25  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGES.
27  *
28  * This software is not designed or intended for use in on-line control of
29  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
30  * the design, construction, operation or maintenance of any nuclear
31  * facility. Licensee represents and warrants that it will not use or
32  * redistribute the Software for such purposes.
33  */

34
35 package com.sun.tools.example.debug.tty;
36
37 import com.sun.jdi.*;
38 import com.sun.jdi.connect.*;
39 import com.sun.jdi.request.EventRequestManager;
40 import com.sun.jdi.request.ExceptionRequest;
41 import com.sun.jdi.request.ThreadStartRequest;
42 import com.sun.jdi.request.ThreadDeathRequest;
43
44 import java.util.*;
45 import java.util.regex.*;
46 import java.io.*;
47
48 class VMConnection {
49
50     private VirtualMachine vm;
51     private Process JavaDoc process = null;
52     private int outputCompleteCount = 0;
53
54     private final Connector connector;
55     private final Map connectorArgs;
56     private final int traceFlags;
57
58     synchronized void notifyOutputComplete() {
59         outputCompleteCount++;
60         notifyAll();
61     }
62
63     synchronized void waitOutputComplete() {
64         // Wait for stderr and stdout
65
if (process != null) {
66             while (outputCompleteCount < 2) {
67                 try {wait();} catch (InterruptedException JavaDoc e) {}
68             }
69         }
70     }
71
72     private Connector findConnector(String JavaDoc name) {
73         List connectors = Bootstrap.virtualMachineManager().allConnectors();
74         Iterator iter = connectors.iterator();
75         while (iter.hasNext()) {
76             Connector connector = (Connector)iter.next();
77             if (connector.name().equals(name)) {
78                 return connector;
79             }
80         }
81         return null;
82     }
83
84     private Map parseConnectorArgs(Connector connector, String JavaDoc argString) {
85         Map arguments = connector.defaultArguments();
86
87         /*
88          * We are parsing strings of the form:
89          * name1=value1,[name2=value2,...]
90          * However, the value1...valuen substrings may contain
91          * embedded comma(s), so make provision for quoting inside
92          * the value substrings. (Bug ID 4285874)
93          */

94         String JavaDoc regexPattern =
95             "(quote=[^,]+,)|" + // special case for quote=.,
96
"(\\w+=)" + // name=
97
"(((\"[^\"]*\")|" + // ( "l , ue"
98
"('[^']*')|" + // 'l , ue'
99
"([^,'\"]+))+,)"; // v a l u e )+ ,
100
Pattern p = Pattern.compile(regexPattern);
101         Matcher m = p.matcher(argString);
102         while (m.find()) {
103             int startPosition = m.start();
104             int endPosition = m.end();
105             if (startPosition > 0) {
106                 /*
107                  * It is an error if parsing skips over any part of argString.
108                  */

109                 throw new IllegalArgumentException JavaDoc
110                     (MessageOutput.format("Illegal connector argument",
111                                           argString));
112             }
113
114             String JavaDoc token = argString.substring(startPosition, endPosition);
115             int index = token.indexOf('=');
116             String JavaDoc name = token.substring(0, index);
117             String JavaDoc value = token.substring(index + 1,
118                                            token.length() - 1); // Remove comma delimiter
119

120             Connector.Argument argument = (Connector.Argument)arguments.get(name);
121             if (argument == null) {
122                 throw new IllegalArgumentException JavaDoc
123                     (MessageOutput.format("Argument is not defined for connector:",
124                                           new Object JavaDoc [] {name, connector.name()}));
125             }
126             argument.setValue(value);
127
128             argString = argString.substring(endPosition); // Remove what was just parsed...
129
m = p.matcher(argString); // and parse again on what is left.
130
}
131         if ((! argString.equals(",")) && (argString.length() > 0)) {
132             /*
133              * It is an error if any part of argString is left over,
134              * unless it was empty to begin with.
135              */

136             throw new IllegalArgumentException JavaDoc
137                 (MessageOutput.format("Illegal connector argument", argString));
138         }
139         return arguments;
140     }
141
142     VMConnection(String JavaDoc connectSpec, int traceFlags) {
143         String JavaDoc nameString;
144         String JavaDoc argString;
145         int index = connectSpec.indexOf(':');
146         if (index == -1) {
147             nameString = connectSpec;
148             argString = "";
149         } else {
150             nameString = connectSpec.substring(0, index);
151             argString = connectSpec.substring(index + 1);
152         }
153
154         connector = findConnector(nameString);
155         if (connector == null) {
156             throw new IllegalArgumentException JavaDoc
157                 (MessageOutput.format("No connector named:", nameString));
158         }
159
160         connectorArgs = parseConnectorArgs(connector, argString);
161         this.traceFlags = traceFlags;
162     }
163         
164     synchronized VirtualMachine open() {
165         if (connector instanceof LaunchingConnector) {
166             vm = launchTarget();
167         } else if (connector instanceof AttachingConnector) {
168             vm = attachTarget();
169         } else if (connector instanceof ListeningConnector) {
170             vm = listenTarget();
171         } else {
172             throw new InternalError JavaDoc
173                 (MessageOutput.format("Invalid connect type"));
174         }
175         vm.setDebugTraceMode(traceFlags);
176         if (vm.canBeModified()){
177             setEventRequests(vm);
178             resolveEventRequests();
179         }
180         /*
181          * Now that the vm connection is open, fetch the debugee
182          * classpath and set up a default sourcepath.
183          * (Unless user supplied a sourcepath on the command line)
184          * (Bug ID 4186582)
185          */

186         if (Env.getSourcePath().length() == 0) {
187             if (vm instanceof PathSearchingVirtualMachine) {
188                 PathSearchingVirtualMachine psvm =
189                     (PathSearchingVirtualMachine) vm;
190                 Env.setSourcePath(psvm.classPath());
191             } else {
192                 Env.setSourcePath(".");
193             }
194         }
195
196         return vm;
197     }
198
199     boolean setConnectorArg(String JavaDoc name, String JavaDoc value) {
200         /*
201          * Too late if the connection already made
202          */

203         if (vm != null) {
204             return false;
205         }
206
207         Connector.Argument argument = (Connector.Argument)connectorArgs.get(name);
208         if (argument == null) {
209             return false;
210         }
211         argument.setValue(value);
212         return true;
213     }
214
215     String JavaDoc connectorArg(String JavaDoc name) {
216         Connector.Argument argument = (Connector.Argument)connectorArgs.get(name);
217         if (argument == null) {
218             return "";
219         }
220         return argument.value();
221     }
222
223     public synchronized VirtualMachine vm() {
224         if (vm == null) {
225             throw new VMNotConnectedException();
226         } else {
227             return vm;
228         }
229     }
230
231     boolean isOpen() {
232         return (vm != null);
233     }
234
235     boolean isLaunch() {
236         return (connector instanceof LaunchingConnector);
237     }
238
239     public void disposeVM() {
240         try {
241             if (vm != null) {
242                 vm.dispose();
243                 vm = null;
244             }
245         } finally {
246             if (process != null) {
247                 process.destroy();
248                 process = null;
249             }
250             waitOutputComplete();
251         }
252     }
253
254     private void setEventRequests(VirtualMachine vm) {
255         EventRequestManager erm = vm.eventRequestManager();
256
257         // Normally, we want all uncaught exceptions. We request them
258
// via the same mechanism as Commands.commandCatchException()
259
// so the user can ignore them later if they are not
260
// interested.
261
// FIXME: this works but generates spurious messages on stdout
262
// during startup:
263
// Set uncaught java.lang.Throwable
264
// Set deferred uncaught java.lang.Throwable
265
Commands evaluator = new Commands();
266         evaluator.commandCatchException
267             (new StringTokenizer("uncaught java.lang.Throwable"));
268
269         ThreadStartRequest tsr = erm.createThreadStartRequest();
270         tsr.enable();
271         ThreadDeathRequest tdr = erm.createThreadDeathRequest();
272         tdr.enable();
273     }
274
275     private void resolveEventRequests() {
276         Env.specList.resolveAll();
277     }
278
279     private void dumpStream(InputStream stream) throws IOException {
280         BufferedReader in =
281             new BufferedReader(new InputStreamReader(stream));
282         int i;
283         try {
284             while ((i = in.read()) != -1) {
285                    MessageOutput.printDirect((char)i);// Special case: use
286
// printDirect()
287
}
288         } catch (IOException ex) {
289             String JavaDoc s = ex.getMessage();
290             if (!s.startsWith("Bad file number")) {
291                   throw ex;
292             }
293             // else we got a Bad file number IOException which just means
294
// that the debuggee has gone away. We'll just treat it the
295
// same as if we got an EOF.
296
}
297     }
298
299     /**
300      * Create a Thread that will retrieve and display any output.
301      * Needs to be high priority, else debugger may exit before
302      * it can be displayed.
303      */

304     private void displayRemoteOutput(final InputStream stream) {
305     Thread JavaDoc thr = new Thread JavaDoc("output reader") {
306         public void run() {
307                 try {
308                     dumpStream(stream);
309                 } catch (IOException ex) {
310                     MessageOutput.fatalError("Failed reading output");
311                 } finally {
312                     notifyOutputComplete();
313                 }
314         }
315     };
316     thr.setPriority(Thread.MAX_PRIORITY-1);
317     thr.start();
318     }
319
320     private void dumpFailedLaunchInfo(Process JavaDoc process) {
321         try {
322             dumpStream(process.getErrorStream());
323             dumpStream(process.getInputStream());
324         } catch (IOException e) {
325             MessageOutput.println("Unable to display process output:",
326                                   e.getMessage());
327         }
328     }
329
330     /* launch child target vm */
331     private VirtualMachine launchTarget() {
332         LaunchingConnector launcher = (LaunchingConnector)connector;
333         try {
334             VirtualMachine vm = launcher.launch(connectorArgs);
335             process = vm.process();
336             displayRemoteOutput(process.getErrorStream());
337             displayRemoteOutput(process.getInputStream());
338             return vm;
339         } catch (IOException ioe) {
340             ioe.printStackTrace();
341             MessageOutput.fatalError("Unable to launch target VM.");
342         } catch (IllegalConnectorArgumentsException icae) {
343             icae.printStackTrace();
344             MessageOutput.fatalError("Internal debugger error.");
345         } catch (VMStartException vmse) {
346             MessageOutput.println("vmstartexception", vmse.getMessage());
347             MessageOutput.println();
348             dumpFailedLaunchInfo(vmse.process());
349             MessageOutput.fatalError("Target VM failed to initialize.");
350         }
351         return null; // Shuts up the compiler
352
}
353
354     /* attach to running target vm */
355     private VirtualMachine attachTarget() {
356         AttachingConnector attacher = (AttachingConnector)connector;
357         try {
358             return attacher.attach(connectorArgs);
359         } catch (IOException ioe) {
360             ioe.printStackTrace();
361             MessageOutput.fatalError("Unable to attach to target VM.");
362         } catch (IllegalConnectorArgumentsException icae) {
363             icae.printStackTrace();
364             MessageOutput.fatalError("Internal debugger error.");
365         }
366         return null; // Shuts up the compiler
367
}
368
369     /* listen for connection from target vm */
370     private VirtualMachine listenTarget() {
371         ListeningConnector listener = (ListeningConnector)connector;
372         try {
373             String JavaDoc retAddress = listener.startListening(connectorArgs);
374             MessageOutput.println("Listening at address:", retAddress);
375             vm = listener.accept(connectorArgs);
376             listener.stopListening(connectorArgs);
377             return vm;
378         } catch (IOException ioe) {
379             ioe.printStackTrace();
380             MessageOutput.fatalError("Unable to attach to target VM.");
381         } catch (IllegalConnectorArgumentsException icae) {
382             icae.printStackTrace();
383             MessageOutput.fatalError("Internal debugger error.");
384         }
385         return null; // Shuts up the compiler
386
}
387 }
388
Popular Tags