001: package org.drools.eclipse.debug.core;
002:
003: import java.text.MessageFormat;
004: import java.util.ArrayList;
005: import java.util.Collections;
006: import java.util.Iterator;
007: import java.util.List;
008:
009: import org.drools.eclipse.DroolsEclipsePlugin;
010: import org.eclipse.debug.core.DebugEvent;
011: import org.eclipse.debug.core.DebugException;
012: import org.eclipse.debug.core.model.IBreakpoint;
013: import org.eclipse.debug.core.model.IStackFrame;
014: import org.eclipse.jdt.debug.core.IJavaThread;
015: import org.eclipse.jdt.internal.debug.core.model.JDIDebugModelMessages;
016: import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
017: import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
018: import org.eclipse.jdt.internal.debug.core.model.JDIThread;
019: import org.mvel.debug.Debugger;
020:
021: import com.sun.jdi.ClassType;
022: import com.sun.jdi.IncompatibleThreadStateException;
023: import com.sun.jdi.IntegerValue;
024: import com.sun.jdi.InvalidStackFrameException;
025: import com.sun.jdi.Location;
026: import com.sun.jdi.Method;
027: import com.sun.jdi.ObjectCollectedException;
028: import com.sun.jdi.ObjectReference;
029: import com.sun.jdi.ReferenceType;
030: import com.sun.jdi.StackFrame;
031: import com.sun.jdi.ThreadReference;
032:
033: /**
034: * Drools Thread supporting MVEL and Java dialect stackframes
035: *
036: */
037: public class DroolsThread extends JDIThread {
038:
039: private List fStackFrames;
040: private boolean fRefreshChildren = true;
041:
042: public DroolsThread(JDIDebugTarget target, ThreadReference thread)
043: throws ObjectCollectedException {
044: super (target, thread);
045: }
046:
047: protected void initialize() throws ObjectCollectedException {
048: super .initialize();
049: fStackFrames = new ArrayList();
050: }
051:
052: public synchronized List computeStackFrames() throws DebugException {
053: return computeStackFrames(fRefreshChildren);
054: }
055:
056: protected synchronized List computeStackFrames(
057: boolean refreshChildren) throws DebugException {
058: if (isSuspended()) {
059: if (isTerminated()) {
060: fStackFrames.clear();
061: } else if (refreshChildren) {
062: List frames = getUnderlyingFrames();
063: int oldSize = fStackFrames.size();
064: int newSize = frames.size();
065: int discard = oldSize - newSize; // number of old frames to discard, if any
066: for (int i = 0; i < discard; i++) {
067: DroolsStackFrame invalid = (DroolsStackFrame) fStackFrames
068: .remove(0);
069: invalid.bind(null, -1);
070: }
071: int newFrames = newSize - oldSize; // number of frames to create, if any
072: int depth = oldSize;
073: for (int i = newFrames - 1; i >= 0; i--) {
074: StackFrame currentFrame = (StackFrame) frames
075: .get(i);
076: //MVEL: create an mvel stack frame when the declaring type is our debugger?
077:
078: DroolsStackFrame customFrame;
079:
080: customFrame = createCustomFrame(this , depth,
081: currentFrame);
082:
083: fStackFrames.add(0, customFrame);
084:
085: depth++;
086: }
087: int numToRebind = Math.min(newSize, oldSize); // number of frames to attempt to rebind
088: int offset = newSize - 1;
089: for (depth = 0; depth < numToRebind; depth++) {
090: DroolsStackFrame oldFrame = (DroolsStackFrame) fStackFrames
091: .get(offset);
092: StackFrame frame = (StackFrame) frames.get(offset);
093: DroolsStackFrame newFrame = (DroolsStackFrame) oldFrame
094: .bind(frame, depth);
095: if (newFrame != oldFrame) {
096: fStackFrames.set(offset, newFrame);
097: }
098: offset--;
099: }
100:
101: }
102: fRefreshChildren = false;
103: } else {
104: return Collections.EMPTY_LIST;
105: }
106: return fStackFrames;
107: }
108:
109: public final static DroolsStackFrame createCustomFrame(
110: DroolsThread thread, int depth, StackFrame currentFrame) {
111: DroolsStackFrame customFrame;
112: Location loc = currentFrame.location();
113: if (loc.declaringType().name().equals(
114: "org.drools.base.mvel.MVELDebugHandler")
115: && loc.method().name().equals("onBreak")) {
116: customFrame = new MVELStackFrame(thread, currentFrame,
117: depth);
118: } else {
119: customFrame = new DroolsStackFrame(thread, currentFrame,
120: depth);
121: }
122: return customFrame;
123: }
124:
125: private List getUnderlyingFrames() throws DebugException {
126: if (!isSuspended()) {
127: // Checking isSuspended here eliminates a race condition in resume
128: // between the time stack frames are preserved and the time the
129: // underlying thread is actually resumed.
130: requestFailed(
131: JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1,
132: null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
133: }
134: try {
135: return getUnderlyingThread().frames();
136: } catch (IncompatibleThreadStateException e) {
137: requestFailed(
138: JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1,
139: e, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
140: } catch (RuntimeException e) {
141: targetRequestFailed(
142: MessageFormat
143: .format(
144: JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2,
145: new String[] { e.toString() }), e);
146: } catch (InternalError e) {
147: targetRequestFailed(
148: MessageFormat
149: .format(
150: JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2,
151: new String[] { e.toString() }), e);
152: }
153: // execution will not reach this line, as
154: // #targetRequestFailed will thrown an exception
155: return null;
156: }
157:
158: protected synchronized void preserveStackFrames() {
159: fRefreshChildren = true;
160: Iterator frames = fStackFrames.iterator();
161: while (frames.hasNext()) {
162: ((DroolsStackFrame) frames.next())
163: .setUnderlyingStackFrame(null);
164: }
165: }
166:
167: protected synchronized void disposeStackFrames() {
168: fStackFrames.clear();
169: fRefreshChildren = true;
170: }
171:
172: protected void popFrame(IStackFrame frame) throws DebugException {
173: JDIDebugTarget target = (JDIDebugTarget) getDebugTarget();
174: if (target.canPopFrames()) {
175: // JDK 1.4 support
176: try {
177: // Pop the frame and all frames above it
178: StackFrame jdiFrame = null;
179: int desiredSize = fStackFrames.size()
180: - fStackFrames.indexOf(frame) - 1;
181: int lastSize = fStackFrames.size() + 1; // Set up to pass the first test
182: int size = fStackFrames.size();
183: while (size < lastSize && size > desiredSize) {
184: // Keep popping frames until the stack stops getting smaller
185: // or popFrame is gone.
186: // see Bug 8054
187: jdiFrame = ((DroolsStackFrame) frame)
188: .getUnderlyingStackFrame();
189: preserveStackFrames();
190: getUnderlyingThread().popFrames(jdiFrame);
191: lastSize = size;
192: size = computeStackFrames().size();
193: }
194: } catch (IncompatibleThreadStateException exception) {
195: targetRequestFailed(
196: MessageFormat
197: .format(
198: JDIDebugModelMessages.JDIThread_exception_popping,
199: new String[] { exception
200: .toString() }),
201: exception);
202: } catch (InvalidStackFrameException exception) {
203: // InvalidStackFrameException can be thrown when all but the
204: // deepest frame were popped. Fire a changed notification
205: // in case this has occured.
206: fireChangeEvent(DebugEvent.CONTENT);
207: targetRequestFailed(exception.toString(), exception);
208: } catch (RuntimeException exception) {
209: targetRequestFailed(
210: MessageFormat
211: .format(
212: JDIDebugModelMessages.JDIThread_exception_popping,
213: new String[] { exception
214: .toString() }),
215: exception);
216: }
217: }
218: }
219:
220: protected void terminated() {
221: super .terminated();
222: }
223:
224: protected void removeCurrentBreakpoint(IBreakpoint bp) {
225: super .removeCurrentBreakpoint(bp);
226: }
227:
228: protected synchronized void suspendedByVM() {
229: super .suspendedByVM();
230: }
231:
232: protected synchronized void resumedByVM() throws DebugException {
233: super .resumedByVM();
234: }
235:
236: protected void setRunning(boolean running) {
237: super .setRunning(running);
238: }
239:
240: protected void dropToFrame(IStackFrame frame) throws DebugException {
241: super .dropToFrame(frame);
242: }
243:
244: protected synchronized void stepToFrame(IStackFrame frame)
245: throws DebugException {
246: super .stepToFrame(frame);
247: }
248:
249: /* (non-Javadoc)
250: * @see org.eclipse.jdt.internal.debug.core.model.JDIThread#newInstance(com.sun.jdi.ClassType, com.sun.jdi.Method, java.util.List)
251: */
252: public ObjectReference newInstance(ClassType receiverClass,
253: Method constructor, List args) throws DebugException {
254: return super .newInstance(receiverClass, constructor, args);
255: }
256:
257: public synchronized void stepOver() throws DebugException {
258:
259: // Detection for active stackframe
260: if (!(getTopStackFrame() instanceof MVELStackFrame)) {
261: super .stepOver();
262: return;
263: }
264:
265: //MVEL step over
266: if (!canStepOver()) {
267: return;
268: }
269:
270: if (!setRemoteOnBreakReturn(Debugger.STEP)) {
271: return;
272: }
273:
274: setRunning(true);
275: preserveStackFrames();
276:
277: try {
278: getUnderlyingThread().resume();
279: } catch (RuntimeException e) {
280: //stepEnd();
281: targetRequestFailed(MessageFormat.format(
282: JDIDebugModelMessages.JDIThread_exception_stepping,
283: new String[] { e.toString() }), e);
284: }
285:
286: }
287:
288: private boolean setRemoteOnBreakReturn(int step_over)
289: throws DebugException {
290:
291: JDIStackFrame top = (JDIStackFrame) getTopStackFrame();
292: if (top == null || (!(top instanceof MVELStackFrame))) {
293: return false;
294: }
295:
296: Iterator handleriter = getVM().classesByName(
297: "org.drools.base.mvel.MVELDebugHandler").iterator();
298: Object debugHandlerClass = handleriter.next();
299:
300: int line = step_over;
301:
302: ReferenceType refType = (ReferenceType) debugHandlerClass;
303: Method m = (Method) refType.methodsByName("setOnBreakReturn")
304: .iterator().next();
305: List args = new ArrayList();
306: IntegerValue lineVal = getVM().mirrorOf(line);
307: //ObjectReference realVal = val.getUnderlyingObject();
308: args.add(lineVal);
309:
310: try {
311: ClassType tt = (ClassType) debugHandlerClass;
312: tt.invokeMethod(getUnderlyingThread(), m, args,
313: ObjectReference.INVOKE_SINGLE_THREADED);
314:
315: } catch (Exception e) {
316: DroolsEclipsePlugin.log(e);
317: return false;
318: }
319: return true;
320: }
321:
322: public synchronized void resume() throws DebugException {
323: // clear up the step over flag. step over button never calls this method.
324: setRemoteOnBreakReturn(Debugger.CONTINUE);
325: super.resume();
326: }
327: }
|