1 package jde.debugger.spec;
4 import com.sun.jdi.request.*;
7 import jde.debugger.JDEException;
10 * MethodBreakpointSpec.java
12 * Funnily, it seems this class actually supports setting breakpoints in
13 * a particular method of an arbitrary filename! since it's very weird, it's
14 * not supported. Let us know if you require such a feature...
16 * Created: Thu Jul 15 15:52:45 1999
20 * @version $Revision: 1.3 $
23 public class MethodBreakpointSpec extends BreakpointSpec {
28 public MethodBreakpointSpec(ReferenceTypeSpec refSpec,
29 String methodName, List methodArgs) {
31 this.methodName = methodName;
32 this.methodArgs = methodArgs;
35 boolean resolve(ReferenceType refType) throws JDEException {
36 if (!isValidMethodName(methodName)) {
37 throw new JDEException("'"+methodName+"' is not a valid method name.");
39 if (!(refType instanceof ClassType)) {
40 throw new JDEException("'"+refType+"' is not a Class");
42 Location location = getLocation((ClassType)refType);
43 if (location == null) {
44 throw new JDEException("Can't set breakpoint on an abstract/native method");
46 BreakpointRequest br = refType.virtualMachine().eventRequestManager().createBreakpointRequest(location);
52 private Location getLocation(ClassType clazz) throws JDEException {
53 Method method = findMatchingMethod(clazz);
54 Location location = method.location();
58 public String getMethodName() {
62 public List getMethodArgs() {
66 public String toString() {
67 StringBuffer buffer = new StringBuffer("break in_method ");
68 if (refSpec instanceof SourceNameReferenceTypeSpec) {
69 buffer.append(((SourceNameReferenceTypeSpec)refSpec).getSourceName());
70 } else if (refSpec instanceof PatternReferenceTypeSpec) {
71 buffer.append(((PatternReferenceTypeSpec)refSpec).getClassPattern());
73 buffer.append(" "+methodName+" ");
74 if (methodArgs != null) {
75 Iterator iter = methodArgs.iterator();
78 while (iter.hasNext()) {
82 buffer.append((String)iter.next());
87 return buffer.toString();
90 private boolean isValidMethodName(String s) {
91 return isJavaIdentifier(s) ||
97 * Compare a method's argument types with a Vector of type names.
98 * Return true if each argument type has a name identical to the
99 * corresponding string in the vector and if the number of
100 * arguments in the method matches the number of names passed
102 private boolean compareArgTypes(Method method, List nameList) {
103 List argTypeNames = method.argumentTypeNames();
106 // If argument counts differ, we can stop here
107 if (argTypeNames.size() != nameList.size()) {
111 // Compare each argument type's name
112 for (int i=0; i<argTypeNames.size(); ++i) {
113 String comp1 = (String)argTypeNames.get(i);
114 String comp2 = (String)nameList.get(i);
115 if (! comp1.equals(comp2)) {
123 * Remove unneeded spaces and expand class names to fully
124 * qualified names, if necessary and possible.
126 private String normalizeArgTypeName(String name)
127 throws JDEException {
129 * Separate the type name from any array modifiers,
130 * stripping whitespace after the name ends
133 StringBuffer typePart = new StringBuffer();
134 StringBuffer arrayPart = new StringBuffer();
136 while (i < name.length()) {
137 char c = name.charAt(i);
138 if (Character.isWhitespace(c) || c == '[') {
139 break; // name is complete
144 while (i < name.length()) {
145 char c = name.charAt(i);
146 if ( (c == '[') || (c == ']') ) {
148 } else if (!Character.isWhitespace(c)) {
149 throw new JDEException("At least one of the arguments of method '"+methodName+"' is invalid.");
153 name = typePart.toString();
156 * When there's no sign of a package name already,
158 * the name to a fully qualified class name
160 if ((name.indexOf('.') == -1) || name.startsWith("*.")) {
162 List refs = new LinkedList(); // XXX to get it to compile
163 // List refs = proc.findClassesMatchingPattern(name);
164 // if more than one class match, take the first, but
166 if (refs.size() > 0) {
167 name = ((ReferenceType)(refs.get(0))).name();
169 if (refs.size() > 1) {
170 // jde.signal(procID, WARNING, "(Method Breakpoint Warning) More than one classes matched resolving an argument for method '"+methodName+"'. Defaulting to the first match.");
173 } catch (IllegalArgumentException e) {
174 // We'll try the name as is
177 name += arrayPart.toString();
182 * Attempt an unambiguous match of the method name and
183 * argument specification to a method. If no arguments
184 * are specified, the method must not be overloaded.
185 * Otherwise, the argument types much match exactly
187 private Method findMatchingMethod(ClassType clazz)
188 throws JDEException {
190 // Normalize the argument string once before looping below.
191 List argTypeNames = null;
192 if (methodArgs != null) {
193 argTypeNames = new ArrayList(methodArgs.size());
194 Iterator iter = methodArgs.iterator();
195 while (iter.hasNext()) {
196 String name = (String)iter.next();
197 name = normalizeArgTypeName(name);
198 argTypeNames.add(name);
202 // Check each method in the class for matches
203 Iterator iter = clazz.methods().iterator();
204 Method firstMatch = null; // first method with matching name
205 Method exactMatch = null; // (only) method with same name & sig
206 int matchCount = 0; // > 1 implies overload
207 while (iter.hasNext()) {
208 Method candidate = (Method)iter.next();
210 if (candidate.name().equals(getMethodName())) {
213 // Remember the first match in case it is the only one
214 if (matchCount == 1) {
215 firstMatch = candidate;
218 // If argument types were specified, check against candidate
219 if ((argTypeNames != null)
220 && compareArgTypes(candidate, argTypeNames) == true) {
221 exactMatch = candidate;
227 // Determine method for breakpoint
228 Method method = null;
229 if (exactMatch != null) {
230 // Name and signature match
232 } else if ((argTypeNames == null) && (matchCount > 0)) {
233 // At least one name matched and no arg types were specified
234 if (matchCount == 1) {
235 method = firstMatch; // Only one match; safe to use it
237 throw new JDEException("Ambiguous method '"+methodName+"'. Specify arguments.");
240 throw new JDEException("No method named '"+methodName+"' in class.");
245 } // MethodBreakpointSpec
248 * $Log: MethodBreakpointSpec.java,v $
249 * Revision 1.3 2003/01/15 06:06:15 paulk
250 * Petter Mahlen's changes.
254 // End of MethodBreakpointSpec.java