KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > tools > example > debug > bdi > MethodBreakpointSpec


1 /*
2  * @(#)MethodBreakpointSpec.java 1.11 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-1999 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.bdi;
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 public class MethodBreakpointSpec extends BreakpointSpec {
45     String JavaDoc methodId;
46     List JavaDoc methodArgs;
47
48     MethodBreakpointSpec(EventRequestSpecList specs,
49                          ReferenceTypeSpec refSpec,
50                          String JavaDoc methodId, List JavaDoc methodArgs) {
51         super(specs, refSpec);
52         this.methodId = methodId;
53         this.methodArgs = methodArgs;
54     }
55
56     /**
57      * The 'refType' is known to match.
58      */

59     void resolve(ReferenceType refType) throws MalformedMemberNameException,
60                                              AmbiguousMethodException,
61                                              InvalidTypeException,
62                                              NoSuchMethodException JavaDoc,
63                                              NoSessionException {
64         if (!isValidMethodName(methodId)) {
65             throw new MalformedMemberNameException(methodId);
66         }
67         if (!(refType instanceof ClassType)) {
68             throw new InvalidTypeException();
69         }
70         Location location = location((ClassType)refType);
71         setRequest(refType.virtualMachine().eventRequestManager()
72                    .createBreakpointRequest(location));
73     }
74
75     private Location location(ClassType clazz) throws
76                                                AmbiguousMethodException,
77                                                NoSuchMethodException JavaDoc,
78                                                NoSessionException {
79         Method method = findMatchingMethod(clazz);
80         Location location = method.location();
81         return location;
82     }
83
84     public String JavaDoc methodName() {
85         return methodId;
86     }
87
88     public List JavaDoc methodArgs() {
89         return methodArgs;
90     }
91
92     public int hashCode() {
93         return refSpec.hashCode() +
94             ((methodId != null) ? methodId.hashCode() : 0) +
95             ((methodArgs != null) ? methodArgs.hashCode() : 0);
96     }
97
98     public boolean equals(Object JavaDoc obj) {
99         if (obj instanceof MethodBreakpointSpec) {
100             MethodBreakpointSpec breakpoint = (MethodBreakpointSpec)obj;
101
102             return methodId.equals(breakpoint.methodId) &&
103                    methodArgs.equals(breakpoint.methodArgs) &&
104                    refSpec.equals(breakpoint.refSpec);
105         } else {
106             return false;
107         }
108     }
109
110     public String JavaDoc errorMessageFor(Exception JavaDoc e) {
111         if (e instanceof AmbiguousMethodException) {
112             return ("Method " + methodName() + " is overloaded; specify arguments");
113             /*
114              * TO DO: list the methods here
115              */

116         } else if (e instanceof NoSuchMethodException JavaDoc) {
117             return ("No method " + methodName() + " in " + refSpec);
118         } else if (e instanceof InvalidTypeException) {
119             return ("Breakpoints can be located only in classes. " +
120                         refSpec + " is an interface or array");
121         } else {
122             return super.errorMessageFor( e);
123         }
124     }
125
126     public String JavaDoc toString() {
127         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("breakpoint ");
128         buffer.append(refSpec.toString());
129         buffer.append('.');
130         buffer.append(methodId);
131         if (methodArgs != null) {
132             Iterator JavaDoc iter = methodArgs.iterator();
133             boolean first = true;
134             buffer.append('(');
135             while (iter.hasNext()) {
136                 if (!first) {
137                     buffer.append(',');
138                 }
139                 buffer.append((String JavaDoc)iter.next());
140                 first = false;
141             }
142             buffer.append(")");
143         }
144         buffer.append(" (");
145         buffer.append(getStatusString());
146         buffer.append(')');
147         return buffer.toString();
148     }
149
150     private boolean isValidMethodName(String JavaDoc s) {
151         return isJavaIdentifier(s) ||
152                s.equals("<init>") ||
153                s.equals("<clinit>");
154     }
155
156     /*
157      * Compare a method's argument types with a Vector of type names.
158      * Return true if each argument type has a name identical to the
159      * corresponding string in the vector (allowing for varargs)
160      * and if the number of arguments in the method matches the
161      * number of names passed
162      */

163     private boolean compareArgTypes(Method method, List JavaDoc nameList) {
164         List JavaDoc argTypeNames = method.argumentTypeNames();
165
166         // If argument counts differ, we can stop here
167
if (argTypeNames.size() != nameList.size()) {
168             return false;
169         }
170
171         // Compare each argument type's name
172
int nTypes = argTypeNames.size();
173         for (int i = 0; i < nTypes; ++i) {
174             String JavaDoc comp1 = (String JavaDoc)argTypeNames.get(i);
175             String JavaDoc comp2 = (String JavaDoc)nameList.get(i);
176             if (! comp1.equals(comp2)) {
177                 /*
178                  * We have to handle varargs. EG, the
179                  * method's last arg type is xxx[]
180                  * while the nameList contains xxx...
181                  * Note that the nameList can also contain
182                  * xxx[] in which case we don't get here.
183                  */

184                 if (i != nTypes - 1 ||
185                     !method.isVarArgs() ||
186                     !comp2.endsWith("...")) {
187                     return false;
188                 }
189                 /*
190                  * The last types differ, it is a varargs
191                  * method and the nameList item is varargs.
192                  * We just have to compare the type names, eg,
193                  * make sure we don't have xxx[] for the method
194                  * arg type and yyy... for the nameList item.
195                  */

196                 int comp1Length = comp1.length();
197                 if (comp1Length + 1 != comp2.length()) {
198                     // The type names are different lengths
199
return false;
200                 }
201                 // We know the two type names are the same length
202
if (!comp1.regionMatches(0, comp2, 0, comp1Length - 2)) {
203                     return false;
204                 }
205                 // We do have xxx[] and xxx... as the last param type
206
return true;
207             }
208         }
209
210         return true;
211     }
212
213   private VirtualMachine vm() {
214     return request.virtualMachine();
215   }
216
217   /**
218      * Remove unneeded spaces and expand class names to fully
219      * qualified names, if necessary and possible.
220      */

221     private String JavaDoc normalizeArgTypeName(String JavaDoc name) throws NoSessionException {
222         /*
223          * Separate the type name from any array modifiers,
224          * stripping whitespace after the name ends.
225          */

226         int i = 0;
227         StringBuffer JavaDoc typePart = new StringBuffer JavaDoc();
228         StringBuffer JavaDoc arrayPart = new StringBuffer JavaDoc();
229         name = name.trim();
230         int nameLength = name.length();
231         /*
232          * For varargs, there can be spaces before the ... but not
233          * within the ... So, we will just ignore the ...
234          * while stripping blanks.
235          */

236         boolean isVarArgs = name.endsWith("...");
237         if (isVarArgs) {
238             nameLength -= 3;
239         }
240
241         while (i < nameLength) {
242             char c = name.charAt(i);
243             if (Character.isWhitespace(c) || c == '[') {
244                 break; // name is complete
245
}
246             typePart.append(c);
247             i++;
248         }
249         while (i < nameLength) {
250             char c = name.charAt(i);
251             if ( (c == '[') || (c == ']')) {
252                 arrayPart.append(c);
253             } else if (!Character.isWhitespace(c)) {
254                 throw new IllegalArgumentException JavaDoc(
255                                                 "Invalid argument type name");
256
257             }
258             i++;
259         }
260
261         name = typePart.toString();
262
263         /*
264          * When there's no sign of a package name already,
265      * try to expand the
266          * the name to a fully qualified class name
267          */

268         if ((name.indexOf('.') == -1) || name.startsWith("*.")) {
269             try {
270                 List JavaDoc refs = specs.runtime.findClassesMatchingPattern(name);
271                 if (refs.size() > 0) { //### ambiguity???
272
name = ((ReferenceType)(refs.get(0))).name();
273                 }
274             } catch (IllegalArgumentException JavaDoc e) {
275                 // We'll try the name as is
276
}
277         }
278         name += arrayPart.toString();
279         if (isVarArgs) {
280             name += "...";
281         }
282         return name;
283     }
284
285     /*
286      * Attempt an unambiguous match of the method name and
287      * argument specification to a method. If no arguments
288      * are specified, the method must not be overloaded.
289      * Otherwise, the argument types much match exactly
290      */

291     private Method findMatchingMethod(ClassType clazz)
292                                         throws AmbiguousMethodException,
293                                                NoSuchMethodException JavaDoc,
294                                                NoSessionException {
295
296         // Normalize the argument string once before looping below.
297
List JavaDoc argTypeNames = null;
298         if (methodArgs() != null) {
299             argTypeNames = new ArrayList JavaDoc(methodArgs().size());
300             Iterator JavaDoc iter = methodArgs().iterator();
301             while (iter.hasNext()) {
302                 String JavaDoc name = (String JavaDoc)iter.next();
303                 name = normalizeArgTypeName(name);
304                 argTypeNames.add(name);
305             }
306         }
307
308         // Check each method in the class for matches
309
Iterator JavaDoc iter = clazz.methods().iterator();
310         Method firstMatch = null; // first method with matching name
311
Method exactMatch = null; // (only) method with same name & sig
312
int matchCount = 0; // > 1 implies overload
313
while (iter.hasNext()) {
314             Method candidate = (Method)iter.next();
315
316             if (candidate.name().equals(methodName())) {
317                 matchCount++;
318
319                 // Remember the first match in case it is the only one
320
if (matchCount == 1) {
321                     firstMatch = candidate;
322                 }
323
324                 // If argument types were specified, check against candidate
325
if ((argTypeNames != null)
326                         && compareArgTypes(candidate, argTypeNames) == true) {
327                     exactMatch = candidate;
328                     break;
329                 }
330             }
331         }
332
333         // Determine method for breakpoint
334
Method method = null;
335         if (exactMatch != null) {
336             // Name and signature match
337
method = exactMatch;
338         } else if ((argTypeNames == null) && (matchCount > 0)) {
339             // At least one name matched and no arg types were specified
340
if (matchCount == 1) {
341                 method = firstMatch; // Only one match; safe to use it
342
} else {
343                 throw new AmbiguousMethodException();
344             }
345         } else {
346             throw new NoSuchMethodException JavaDoc(methodName());
347         }
348         return method;
349     }
350 }
351
Popular Tags