1 package jde.debugger.spec;
4 import com.sun.jdi.event.*;
5 import com.sun.jdi.request.*;
8 import jde.debugger.Protocol;
9 import jde.debugger.JDE;
10 import jde.debugger.JDEException;
11 import jde.debugger.SessionManager;
14 * EventRequestSpec.java
16 * A request specification. This is used for watchpoints, exception-catches,
17 * and breakpoints, and provides a mechanism for implementing deferral.
19 * The intuition is that the user should be allowed to specify things like
20 * breakpoints, even though the corresponding classes haven't been loaded
23 * When the user does a, for example, "break on_line test.Test 42", jdebug
24 * tries to find if test.Test has been loaded. If it has, it tries to set
25 * the breakpoint, and sends an error on failure.
27 * If, however, no class matching test.Test exists, jdebug places this
28 * "spec" in a list, and each time a class is prepared, matches the class
29 * with the spec. If the spec matches, it tries to set the breakpoint /
30 * watchpoint / exception-catch. If it works, fine, else it sends the
33 * This also allows for neat things like setting breakpoints on source file
34 * + line number combinations, since each reference type (given it was
35 * compiled with debug info) also contains the source file name in it.
37 * Information that would normally be stuck right into the actual requests,
38 * for example a thread filter, is stored in the spec until the time it can
39 * resolve the request. At that time, it is set in {@link #setRequest}.
43 * Note that as of now, when the doc is being written, there is no way of
44 * ascertaining if the user mistyped the referencetype name/pattern, since
45 * jdebug will just wait <i>ad infinitum</i> for that class to be prepared.
47 * Created: Thu Jul 15 12:17:34 1999
54 abstract public class EventRequestSpec implements Protocol {
56 private final Long m_ID;
60 * While setting some specs, the user is allowed to specify a boolean
61 * expression that must evaluate to true if the event is to be passed
62 * on to the user. This expression is stored in the EventRequest object
63 * as a property. On an event, the EventRequest object is also passed,
64 * and the property can then be extracted, evaluated, and
65 * handled correspondingly
67 public static final Object expressionKey = "expr";
68 private String expr = null;
70 public EventRequestSpec(ReferenceTypeSpec refSpec) {
71 this.refSpec = refSpec;
73 m_ID = SessionManager.generateObjectID();
77 public void setExpression(String expr) {
80 request.putProperty(expressionKey, expr);
84 * For specs that allow for it,
85 * the {@link #thread thread} object is either null, a Long, or a
86 * String. Depending on the type, it is matched at the time the
87 * breakpoint is hit. If it matches the thread, the breakpoint is
90 public static final Object threadKey = "thread";
91 private Object thread = null;
92 public void setThread(Object thread) {
95 request.putProperty(threadKey, thread);
99 * Determines the suspend policy for the corresponding event. See
100 * {@link jde.debugger.EventHandler EventHandler} for more details
102 * Note that the request needs to be disabled for us to be able to
105 private int suspendPolicy = EventRequest.SUSPEND_ALL; // the default
106 public void setSuspendPolicy(int policy) {
107 this.suspendPolicy = policy;
108 if (request != null) {
109 request.setSuspendPolicy(policy);
110 // System.out.println("XXX:"+((request.suspendPolicy() == EventRequest.SUSPEND_NONE)?"none":"not none"));
115 * Stores a list of class filters that are to be applied to the event
116 * request when it gets resolved. This will restrict any events from
117 * being reported only if they match the class filters.
119 * Not all event-requests support class filters. This filters will be
120 * silently ignored for event-requests that do not support them.
122 private List classFilters = null;
123 public void setClassFilters(List filters) {
124 this.classFilters = filters;
126 installClassFilters(request);
130 * Install class filters.
131 * Note that the request needs to be disabled for us to be able to
134 private void installClassFilters(EventRequest request) {
135 if (classFilters == null) return;
136 Iterator iter = classFilters.iterator();
137 while (iter.hasNext()) {
138 String f = iter.next().toString();
139 if (request instanceof ClassPrepareRequest) {
140 ((ClassPrepareRequest)request).addClassFilter(f);
141 } else if (request instanceof ClassUnloadRequest) {
142 ((ClassUnloadRequest)request).addClassFilter(f);
143 } else if (request instanceof ExceptionRequest) {
144 ((ExceptionRequest)request).addClassFilter(f);
145 } else if (request instanceof WatchpointRequest) {
146 ((WatchpointRequest)request).addClassFilter(f);
153 * Stores a list of class exclusion filters that are to be applied to
155 * request when it gets resolved. This will restrict any events from
156 * being reported only if they do <b>not</b> match the class ex-filters.
158 * Not all event-requests support class ex-filters. This filters will be
159 * silently ignored for event-requests that do not support them.
161 private List classExFilters = null;
162 public void setClassExFilters(List filters) {
163 this.classExFilters = filters;
165 installClassExFilters(request);
169 * Install class exclusion filters.
170 * Note that the request needs to be disabled for us to be able to
173 private void installClassExFilters(EventRequest request) {
174 if (classExFilters == null) return;
175 Iterator iter = classExFilters.iterator();
176 while (iter.hasNext()) {
177 String f = iter.next().toString();
178 if (request instanceof ClassPrepareRequest) {
179 ((ClassPrepareRequest)request).addClassExclusionFilter(f);
180 } else if (request instanceof ClassUnloadRequest) {
181 ((ClassUnloadRequest)request).addClassExclusionFilter(f);
182 } else if (request instanceof ExceptionRequest) {
183 ((ExceptionRequest)request).addClassExclusionFilter(f);
184 } else if (request instanceof WatchpointRequest) {
185 ((WatchpointRequest)request).addClassExclusionFilter(f);
193 * Unlike the original javadt (from which most of the spec code comes,
194 * we do not maintain three spec states, ie, resolved, unresolved, and
195 * error. In our case, on an error, we simply remove the spec from the
196 * list of specs being maintained by the application, and inform the
197 * jde of this fact (that there was an error resolving the spec)
198 * (using app.removeSpecAndInformJDE(this))
200 * XXX see if the above needs to be changed
202 * Consequently, we only need keep track of if we're resolved yet or
205 boolean isResolved = false;
208 * Used to cross-reference the EventRequest to its
211 static public final Object specPropertyKey = "spec";
214 * The reference type spec for this event request spec: this should
215 * match the ReferenceType for the spec to be
218 ReferenceTypeSpec refSpec;
221 * The EventRequest corresponding to this spec. This
222 * is set when the spec resolves successfully.
224 EventRequest request = null;
226 /** get the id corresponding to this spec */
227 public Long getID() { return m_ID; }
230 * sets the request up. This is called when a resolve succedes.
232 void setRequest(EventRequest request) {
233 this.request = request;
234 // put a link to this spec in the request itself. a sort of
236 request.putProperty(specPropertyKey, this);
237 request.putProperty(threadKey, thread);
238 request.putProperty(expressionKey, expr);
239 request.setSuspendPolicy(suspendPolicy);
240 installClassFilters(request);
241 installClassExFilters(request);
242 // System.out.println("YYY:"+((request.suspendPolicy() == EventRequest.SUSPEND_NONE)?"none":"not none"));
247 public EventRequest getEventRequest() { return request; }
250 * This function is called to resolve an {@link EventRequestSpec} when
251 * the ReferenceType is known to match
253 * if any errors occur at any time during resolution of the event-
254 * requestspec, its entry in the {@link EventRequestSpecList} is
255 * removed, and jde informed about it
257 * @return true if the resolution was successful
259 abstract boolean resolve(ReferenceType refType) throws JDEException;
262 * This function is called after each new class is loaded. If this
263 * spec hasn't been resolved yet, it's attempted to be resolved. the
264 * handling is almost exactly the same as that in
265 * {@link #attemptImmediateResolve}
268 public void attemptResolve(ReferenceType refType, Integer procID) throws JDEException {
269 if (!isResolved() && refSpec.matches(refType)) {
270 if (resolve(refType)) {
271 JDE.debug(EVENTS, "resolve succeeded: " + refType.name());
272 setIsResolved(procID);
278 * Attempts to resolve the eventRequestSpec immediately. There are
279 * three possibilities:
281 * <li> The corresponding class hasn't been loaded. the method returns
283 * <li> The class has been loaded, and the resolution is successful.
284 * The method returns normally, having set the isResolved flag in this
286 * <li> The class has been loaded, but there was an error trying to
287 * resolve this spec. An exception is raised, and is caught in this
288 * method. This spec is then removed from the spec list kept in the
289 * Application object, and jde informed that this spec could not be
290 * resolved, so that the UI can take appropriate actions (for example
291 * removing the highlighting of a breakpoint)
294 void attemptImmediateResolve(VirtualMachine vm, Integer procID) throws JDEException {
295 Iterator iter = vm.allClasses().iterator();
297 // XXX - I added the !isResolved condition, to save some loop iterations.
298 // Since I don't fully understand it, it could be a bug, but I think not. / Petter
299 while (iter.hasNext() && !isResolved) {
300 ReferenceType refType = (ReferenceType)iter.next();
301 if (refSpec.matches(refType)) {
302 if (resolve(refType)) {
303 setIsResolved(procID);
310 * @return true if this spec has been resolved.
312 public boolean isResolved() {
317 * set resolved status and notify Emacs.
319 public void setIsResolved(Integer procID) {
321 JDE.signal(procID, SPEC_RESOLVED, m_ID.toString(), NOQUOTE);
324 boolean isJavaIdentifier(String s) {
325 if (s.length() == 0) {
329 if (! Character.isJavaIdentifierStart(s.charAt(0))) {
333 for (int i = 1; i < s.length(); i++) {
334 if (! Character.isJavaIdentifierPart(s.charAt(i))) {
342 } // EventRequestSpec
345 * $Log: EventRequestSpec.java,v $
346 * Revision 1.4 2003/01/15 06:06:15 paulk
347 * Petter Mahlen's changes.
351 // End of EventRequestSpec.java