Let’s write a plugin for the Flex Builder debugger. This will be a simple panel called Expression Tracker, which is like the Expressions view except that it does not refresh its displayed values each time you step. Don’t expect anything useful or beautiful here; this is just a barely-functional sample with a pretty rotten UI. But it’s a start.
I should warn you that creating Eclipse plugins takes a large investment of effort to understand how they fit together.
You’ll need to be using the plugin-based version of Flex Builder rather than the standalone version. This means that first, you have to install Eclipse version 3.1.2 from http://www.eclipse.org. Then, you have to install the plugin version of Flex Builder:
The standalone version of Flex Builder is only for writing and debugging Flex applications. But the plugin version is a set of plugins that you install on top of Eclipse, to enable the creation of Flex projects in addition to other types of projects. Flex Builder plugins are written in Java.
File > New > Project; Plug-in Development > Plug-in Project.
Project name: “ExpressionTracker”. Click Next, then Next.
Use the “Plug-in with a view” template, so Eclipse will fill in some boilerplate code for us:
Click Next, and change the classname and a few other settings as follows. The “View Class Name” is the name of the Java class; the “View Name” is the name displayed to the user in the tab for that view; and the “View Category ID” and “View Category Name” control where it shows up under “Window > Show View > Other”:
The above settings will cause your view to show up in the “Flex” category
of views. If you would rather have your plugin show up in the “Debug”
category, then use a View Category ID of org.eclipse.debug.ui
, and a view
category name of “Debug”. Or, make your own new category if you want, such
as “Acme Awesome Flex Extensions.”
Click Finish.
Let’s see what we have so far. Select the ExpressionConsole project in the Package Explorer view, then do Run > Run As > Eclipse Application. Then, in the newly launched Eclipse, Window > Show View > Other; Debug > Expression Tracker.
Hey, it worked! Okay, now we get to the interesting part.
Start by opening ExpressionTrackerView.java
and exploring for a bit. The
various Eclipse templates are very useful for showing you how to hook
everything together. In here, you will see some simple examples of
context-menu commands, double-click handlers, and so on.
Insert these two functions into ExpressionTrackerPlugin.java
. You should
put these in every Eclipse plugin you make, and whenever you have caught an
exception that indicate an error condition, you should call
«YourPluginClass».log()
, to send it to the “Error Log” view:
/**
* Logs the given status to this plug-in's error log.
*
* @param message
* general message, e.g. "Error during initialization"
* @param t
* exception associated with this error, or null
*/
public static void log(String message, Throwable t) {
getDefault().getLog().log(createStatusError(message, t));
}
/**
* Create and return an IStatus object with ERROR severity and the given
* message and exception.
*/
public static IStatus createStatusError(String message, Throwable t) {
if (message == null) {
message = t.getLocalizedMessage();
if (message == null)
message = "";
}
return new Status(IStatus.ERROR, getDefault().getBundle()
.getSymbolicName(), IStatus.ERROR, message, t);
}
Replace your ExpressionTrackerView.java
with this completed
version.
Let’s go through that new version and look at the interesting debugger-related parts. Given an expression, how do you get its value? Answer: You get a reference to Eclipse’s global “expression manager;” tell it to create an expression; tell that expression to evaluate itself in a specified context (stack frame); and then wait until Eclipse sends you an event telling you the evaluation has completed. The relevant source:
ExpressionTrackerView
constructor: Start listening for all debug events.
public ExpressionTrackerView() {
// We register to be notified of all debug-related events, so that
// we will be notified whenever an expression has been evaluated.
DebugPlugin.getDefault().addDebugEventListener(this);
}
ExpressionAndValue
constructor: the user has said to add a new expression to
the view. Create it, and tell it to evaluate itself.
// Get the expression manager, and create a new watch expression
IExpressionManager expressionManager = DebugPlugin.getDefault().getExpressionManager();
watchExpr = expressionManager.newWatchExpression(expr);
// Figure out the "context" of this watch expression -- that is, which
// stack frame is currently selected in Eclipse's "Debug" view?
IDebugElement debugElement = null;
IAdaptable debugContext = DebugUITools.getDebugContext();
if (debugContext != null)
debugElement = (IDebugElement) debugContext.getAdapter(IDebugElement.class);
if (debugElement == null) {
value = "<no debug context>";
} else {
// Have the watch expression begin evaluating itself. When it is
// done, it will dispatch a DebugEvent, which we will see in our
// handleDebugEvents() function.
value = "...";
watchExpr.setExpressionContext(debugElement);
watchExpr.evaluate();
}
ExpressionTrackerView.handleDebugEvents()
: Called by Eclipse whenever any
debugger-related event takes place – a process starts or terminates, a
breakpoint is hit, etc. Our code will look for debug events that indicate that
one of our expressions has been evaluated, and when it has, call
ExpressionAndValue.doneEvaluating()
:
public void handleDebugEvents(DebugEvent[] events) {
for (int i=0; i<events.length; ++i) {
DebugEvent event = events[i];
if (event.getKind() == DebugEvent.CHANGE) {
Object source = event.getSource();
if (source instanceof IWatchExpression) {
for (int j=0; j<items.size(); ++j) {
ExpressionAndValue item = (ExpressionAndValue) items.get(j);
if (item.watchExpr == source) {
item.doneEvaluating();
break;
}
}
}
}
}
}
ExpressionAndValue.doneEvaluating()
: Check if the expression evaluation
encountered errors, such as syntax errors. If so, display the error;
otherwise, display the vlaue.
if (watchExpr.hasErrors()) {
String[] errorMessages = watchExpr.getErrorMessages();
if (errorMessages.length > 0) {
// We should really display all the error messages,
// not just the first...
this.value = errorMessages[0];
} else {
this.value = "Error";
}
} else {
IValue exprValue = watchExpr.getValue();
if (exprValue != null)
this.value = exprValue.getValueString();
else
this.value = "";
}
That is pretty much all the debugger-related functionality in the code. Give it a try now. Run a child instance of Eclipse again. Create a Flex Builder project. Open the Expression Tracker view. Right-click, and add an expression or two.
A masterpiece.
The main thing you need to know is: File > Export > Deployable plug-ins and fragments. This command will package up your plugin in a form that is easy to publish.