KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * @(#)BreakpointSpec.java 1.28 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.request.*;
39
40 import java.util.ArrayList JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Iterator JavaDoc;
43
44 class BreakpointSpec extends EventRequestSpec {
45     String JavaDoc methodId;
46     List JavaDoc methodArgs;
47     int lineNumber;
48
49     BreakpointSpec(ReferenceTypeSpec refSpec, int lineNumber) {
50         super(refSpec);
51         this.methodId = null;
52         this.methodArgs = null;
53         this.lineNumber = lineNumber;
54     }
55
56     BreakpointSpec(ReferenceTypeSpec refSpec, String JavaDoc methodId,
57                    List JavaDoc methodArgs) throws MalformedMemberNameException {
58         super(refSpec);
59         this.methodId = methodId;
60         this.methodArgs = methodArgs;
61         this.lineNumber = 0;
62         if (!isValidMethodName(methodId)) {
63             throw new MalformedMemberNameException(methodId);
64         }
65     }
66
67     /**
68      * The 'refType' is known to match, return the EventRequest.
69      */

70     EventRequest resolveEventRequest(ReferenceType refType)
71                            throws AmbiguousMethodException,
72                                   AbsentInformationException,
73                                   InvalidTypeException,
74                                   NoSuchMethodException JavaDoc,
75                                   LineNotFoundException {
76         Location location = location(refType);
77     if (location == null) {
78         throw new InvalidTypeException();
79     }
80         EventRequestManager em = refType.virtualMachine().eventRequestManager();
81         EventRequest bp = em.createBreakpointRequest(location);
82         bp.setSuspendPolicy(suspendPolicy);
83         bp.enable();
84         return bp;
85     }
86
87     String JavaDoc methodName() {
88         return methodId;
89     }
90
91     int lineNumber() {
92         return lineNumber;
93     }
94
95     List JavaDoc methodArgs() {
96         return methodArgs;
97     }
98
99     boolean isMethodBreakpoint() {
100         return (methodId != null);
101     }
102
103     public int hashCode() {
104         return refSpec.hashCode() + lineNumber +
105             ((methodId != null) ? methodId.hashCode() : 0) +
106             ((methodArgs != null) ? methodArgs.hashCode() : 0);
107     }
108
109     public boolean equals(Object JavaDoc obj) {
110         if (obj instanceof BreakpointSpec) {
111             BreakpointSpec breakpoint = (BreakpointSpec)obj;
112
113             return ((methodId != null) ?
114                         methodId.equals(breakpoint.methodId)
115                       : methodId == breakpoint.methodId) &&
116                    ((methodArgs != null) ?
117                         methodArgs.equals(breakpoint.methodArgs)
118                       : methodArgs == breakpoint.methodArgs) &&
119                    refSpec.equals(breakpoint.refSpec) &&
120                    (lineNumber == breakpoint.lineNumber);
121         } else {
122             return false;
123         }
124     }
125
126     String JavaDoc errorMessageFor(Exception JavaDoc e) {
127         if (e instanceof AmbiguousMethodException) {
128             return (MessageOutput.format("Method is overloaded; specify arguments",
129                                          methodName()));
130             /*
131              * TO DO: list the methods here
132              */

133         } else if (e instanceof NoSuchMethodException JavaDoc) {
134             return (MessageOutput.format("No method in",
135                                          new Object JavaDoc [] {methodName(),
136                                                         refSpec.toString()}));
137         } else if (e instanceof AbsentInformationException) {
138             return (MessageOutput.format("No linenumber information for",
139                                          refSpec.toString()));
140         } else if (e instanceof LineNotFoundException) {
141             return (MessageOutput.format("No code at line",
142                                          new Object JavaDoc [] {new Long JavaDoc (lineNumber()),
143                                                         refSpec.toString()}));
144         } else if (e instanceof InvalidTypeException) {
145             return (MessageOutput.format("Breakpoints can be located only in classes.",
146                                          refSpec.toString()));
147         } else {
148             return super.errorMessageFor( e);
149         }
150     }
151
152     public String JavaDoc toString() {
153         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(refSpec.toString());
154         if (isMethodBreakpoint()) {
155             buffer.append('.');
156             buffer.append(methodId);
157             if (methodArgs != null) {
158                 Iterator JavaDoc iter = methodArgs.iterator();
159                 boolean first = true;
160                 buffer.append('(');
161                 while (iter.hasNext()) {
162                     if (!first) {
163                         buffer.append(',');
164                     }
165                     buffer.append((String JavaDoc)iter.next());
166                     first = false;
167                 }
168                 buffer.append(")");
169             }
170         } else {
171             buffer.append(':');
172             buffer.append(lineNumber);
173         }
174         return MessageOutput.format("breakpoint", buffer.toString());
175     }
176
177     private Location location(ReferenceType refType) throws
178                                     AmbiguousMethodException,
179                                     AbsentInformationException,
180                                     NoSuchMethodException JavaDoc,
181                                     LineNotFoundException {
182         Location location = null;
183         if (isMethodBreakpoint()) {
184             Method method = findMatchingMethod(refType);
185             location = method.location();
186         } else {
187             // let AbsentInformationException be thrown
188
List JavaDoc locs = refType.locationsOfLine(lineNumber());
189             if (locs.size() == 0) {
190                 throw new LineNotFoundException();
191             }
192             // TO DO: handle multiple locations
193
location = (Location)locs.get(0);
194             if (location.method() == null) {
195                 throw new LineNotFoundException();
196             }
197         }
198         return location;
199     }
200
201     private boolean isValidMethodName(String JavaDoc s) {
202         return isJavaIdentifier(s) ||
203                s.equals("<init>") ||
204                s.equals("<clinit>");
205     }
206
207     /*
208      * Compare a method's argument types with a Vector of type names.
209      * Return true if each argument type has a name identical to the
210      * corresponding string in the vector (allowing for varars)
211      * and if the number of arguments in the method matches the
212      * number of names passed
213      */

214     private boolean compareArgTypes(Method method, List JavaDoc nameList) {
215         List JavaDoc argTypeNames = method.argumentTypeNames();
216
217         // If argument counts differ, we can stop here
218
if (argTypeNames.size() != nameList.size()) {
219             return false;
220         }
221
222         // Compare each argument type's name
223
int nTypes = argTypeNames.size();
224         for (int i = 0; i < nTypes; ++i) {
225             String JavaDoc comp1 = (String JavaDoc)argTypeNames.get(i);
226             String JavaDoc comp2 = (String JavaDoc)nameList.get(i);
227             if (! comp1.equals(comp2)) {
228                 /*
229                  * We have to handle varargs. EG, the
230                  * method's last arg type is xxx[]
231                  * while the nameList contains xxx...
232                  * Note that the nameList can also contain
233                  * xxx[] in which case we don't get here.
234                  */

235                 if (i != nTypes - 1 ||
236                     !method.isVarArgs() ||
237                     !comp2.endsWith("...")) {
238                     return false;
239                 }
240                 /*
241                  * The last types differ, it is a varargs
242                  * method and the nameList item is varargs.
243                  * We just have to compare the type names, eg,
244                  * make sure we don't have xxx[] for the method
245                  * arg type and yyy... for the nameList item.
246                  */

247                 int comp1Length = comp1.length();
248                 if (comp1Length + 1 != comp2.length()) {
249                     // The type names are different lengths
250
return false;
251                 }
252                 // We know the two type names are the same length
253
if (!comp1.regionMatches(0, comp2, 0, comp1Length - 2)) {
254                     return false;
255                 }
256                 // We do have xxx[] and xxx... as the last param type
257
return true;
258             }
259         }
260
261         return true;
262     }
263
264
265     /*
266      * Remove unneeded spaces and expand class names to fully
267      * qualified names, if necessary and possible.
268      */

269     private String JavaDoc normalizeArgTypeName(String JavaDoc name) {
270         /*
271          * Separate the type name from any array modifiers,
272          * stripping whitespace after the name ends
273          */

274         int i = 0;
275         StringBuffer JavaDoc typePart = new StringBuffer JavaDoc();
276         StringBuffer JavaDoc arrayPart = new StringBuffer JavaDoc();
277         name = name.trim();
278         int nameLength = name.length();
279         /*
280          * For varargs, there can be spaces before the ... but not
281          * within the ... So, we will just ignore the ...
282          * while stripping blanks.
283          */

284         boolean isVarArgs = name.endsWith("...");
285         if (isVarArgs) {
286             nameLength -= 3;
287         }
288         while (i < nameLength) {
289             char c = name.charAt(i);
290             if (Character.isWhitespace(c) || c == '[') {
291                 break; // name is complete
292
}
293             typePart.append(c);
294             i++;
295         }
296         while (i < nameLength) {
297             char c = name.charAt(i);
298             if ( (c == '[') || (c == ']')) {
299                 arrayPart.append(c);
300             } else if (!Character.isWhitespace(c)) {
301                 throw new IllegalArgumentException JavaDoc
302                     (MessageOutput.format("Invalid argument type name"));
303             }
304             i++;
305         }
306         name = typePart.toString();
307
308         /*
309          * When there's no sign of a package name already, try to expand the
310          * the name to a fully qualified class name
311          */

312         if ((name.indexOf('.') == -1) || name.startsWith("*.")) {
313             try {
314                 ReferenceType argClass = Env.getReferenceTypeFromToken(name);
315                 if (argClass != null) {
316                     name = argClass.name();
317                 }
318             } catch (IllegalArgumentException JavaDoc e) {
319                 // We'll try the name as is
320
}
321         }
322         name += arrayPart.toString();
323         if (isVarArgs) {
324             name += "...";
325         }
326         return name;
327     }
328
329     /*
330      * Attempt an unambiguous match of the method name and
331      * argument specification to a method. If no arguments
332      * are specified, the method must not be overloaded.
333      * Otherwise, the argument types much match exactly
334      */

335     private Method findMatchingMethod(ReferenceType refType)
336                                         throws AmbiguousMethodException,
337                                                NoSuchMethodException JavaDoc {
338
339         // Normalize the argument string once before looping below.
340
List JavaDoc argTypeNames = null;
341         if (methodArgs() != null) {
342             argTypeNames = new ArrayList JavaDoc(methodArgs().size());
343             Iterator JavaDoc iter = methodArgs().iterator();
344             while (iter.hasNext()) {
345                 String JavaDoc name = (String JavaDoc)iter.next();
346                 name = normalizeArgTypeName(name);
347                 argTypeNames.add(name);
348             }
349         }
350
351         // Check each method in the class for matches
352
Iterator JavaDoc iter = refType.methods().iterator();
353         Method firstMatch = null; // first method with matching name
354
Method exactMatch = null; // (only) method with same name & sig
355
int matchCount = 0; // > 1 implies overload
356
while (iter.hasNext()) {
357             Method candidate = (Method)iter.next();
358
359             if (candidate.name().equals(methodName())) {
360                 matchCount++;
361
362                 // Remember the first match in case it is the only one
363
if (matchCount == 1) {
364                     firstMatch = candidate;
365                 }
366
367                 // If argument types were specified, check against candidate
368
if ((argTypeNames != null)
369                         && compareArgTypes(candidate, argTypeNames) == true) {
370                     exactMatch = candidate;
371                     break;
372                 }
373             }
374         }
375
376         // Determine method for breakpoint
377
Method method = null;
378         if (exactMatch != null) {
379             // Name and signature match
380
method = exactMatch;
381         } else if ((argTypeNames == null) && (matchCount > 0)) {
382             // At least one name matched and no arg types were specified
383
if (matchCount == 1) {
384                 method = firstMatch; // Only one match; safe to use it
385
} else {
386                 throw new AmbiguousMethodException();
387             }
388         } else {
389             throw new NoSuchMethodException JavaDoc(methodName());
390         }
391         return method;
392     }
393 }
394
Popular Tags