Sylvain Wallez wrote:
Christopher Oliver wrote:
I started looking into how I could get a meaningful stack trace (with location information) spanning (possibly nested) invocations of the sitemap, flowscript, and JXTemplateGenerator.
<snip>
WDYT?
/me thinks it's great!
Some low-level remarks, however:
- we need a "popStackFrame()" method, since once a component has been executed successfully and execution continues in its following siblings, it should no longer appear in the stack trace
The idea is that this stack trace is created during exception processing:
try {
do whatever
} catch (Exception e) {
Cocoon.addCocoonStackTrace("failed to do whatever", "comp", "method", uri, line, column);
throw e;
}
Thus, during normal processing there is no overhead. That's why there's no popStackFrame().
Ok, I see.
- is the "message" parameter really needed? It's only meaningful for the statement where the error occured, and will be present in the Java exception that is raised.
I guess you're right, but my thinking was that additional information about the call site could be useful. If there's no additional information you can just pass null.
- consequently, to minimize performance overhead, I think it would be better to pass a single StackTraceElement parameter (or "CocoonStackFrame"?), since these objects can be pre-allocated at script/template/sitemap load time and are immutable afterwards.
See above.
- I don't like much putting this on the "Cocoon" class. What about creating a "org.apache.cocoon.util.debug" package holding the various classes that will certainly follow this first enhancement. I'm thinking to a global debugger that may be built using these stack frames.
This approach was only designed to support exception reporting, not to support debug tracing or to develop a debugger. For those purposes a different design is required.
Mmmh... if we push and pop stack frame indications, isn't it enough to build a debugger?
The runtime part of the debugger can be a optional listener in add/popStackFrame which suspends the execution when a breakpoint is encountered (detected using the stack element's location).
And we can also associate an additional object to a StackTraceElement that will give access to the variables in the element's scope. This will be e.g. an InvokeContext for the TreeProcessor or a [JXPath|Jexl]Context for JXTemplate. This allows the debugger do display and even modify the variables that drive the current request's execution.
The cost is two method calls per stack frame (push and pop), which implementation can be reduced to a single test against null when no stacktrace nor debugging is wanted.
public class StackFrameRecorder {
public static void pushStackFrame(Map ObjectModel, CocoonStackFrame frame, Object frameData)
public static void popStackFrame(Map ObjectModel)
}
The CocoonStackFrame, along with the location information you described, will also have a method to wrap the frame-specific data into e.g. a standard Map that will be used by the debugger to display and modify "variables". That way, the debugger doesn't have to handle each particular kind of frameData, but the conversion cost is only to be paid when the debugger wants to display them.
public abstract class CocoonStackFrame {
public String getURI() // and other location properties
public abstract Map getVariables(Object frameData);
}Need to think more about the details, but the small cost of the two method calls per frame may really be worth it.
Sylvain
-- Sylvain Wallez Anyware Technologies http://www.apache.org/~sylvain http://www.anyware-tech.com { XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects } Orixo, the opensource XML business alliance - http://www.orixo.com
