| |
Package Name | Comment | org.bar | | org.foo | | org.foo.ant | | org.foo.myapp | | org.netbeans.api.debugger |
package
The NetBeans Debugger Core API definition. Debugger Core API interfaces
allows to install differrent debugger inlementations to one IDE, and
share some UI components among them.
Basic debugger model
Debugger Core API represents debugger as some tree structure. {@link
org.netbeans.api.debugger.DebuggerManager} represents root of this
tree. It manages list of {@link org.netbeans.api.debugger.Breakpoint}s,
{@link org.netbeans.api.debugger.Watch}es and running {@link
org.netbeans.api.debugger.Session}s. All watches and breakpoints
registerred here are shared for all running sessions.
{@link
org.netbeans.api.debugger.Session} represents one process or
application running in debug mode. Each Session manages list of
supported programming languages. Support for each programming language
is represented by some instance of {@link
org.netbeans.api.debugger.DebuggerEngine}. DebuggerEngine is a main
intergation point for all Debugger Plug-ins. Most of Service Providers
(like {@link
org.netbeans.spi.debugger.ActionsProvider} or different Models) should
be registered for
some concrete type of DebuggerEngine.
{@link org.netbeans.api.debugger.DebuggerManager} | |- {@link org.netbeans.api.debugger.Breakpoint}(s) | |- {@link org.netbeans.api.debugger.Watch}(es) | |- {@link org.netbeans.api.debugger.Session}(s) <programming language 1 -> {@link org.netbeans.api.debugger.DebuggerEngine} 1> <programming language 2 -> {@link org.netbeans.api.debugger.DebuggerEngine} 2> ...
One DebuggerEngine can manage more than one language. And it can be
used for more than one Session. In extreme example, there may be one
DebuggerManager only for several different sessions and for many
different languages.
The only way how to add some language, session or engine to this tree
is method {@link
org.netbeans.api.debugger.DebuggerManager#startDebugging(DebuggerInfo)}.
The only method how to remove something is {@link
org.netbeans.api.debugger.DebuggerEngine.Destructor}.
Exension of basic model - lookups,
Meta-inf/debugger
Basic debugger model is very simple, and it should be extended by some
additional services (see Debugger
SPI documentation for default set of additional services). As the
Debugger API interfaces should be (and are) final, we use lookup
pattern for this purpose.
List of 'extensible' interfaces:
- {@link org.netbeans.api.debugger.DebuggerManager}: methods {@link
org.netbeans.api.debugger.DebuggerManager#lookup(String,Class)}
and {@link
org.netbeans.api.debugger.DebuggerManager#lookupFirst(String,Class)}
- {@link org.netbeans.api.debugger.DebuggerInfo}: methods {@link
org.netbeans.api.debugger.DebuggerInfo#lookup(String,Class)} and {@link
org.netbeans.api.debugger.DebuggerInfo#lookupFirst(String,Class)}
- {@link org.netbeans.api.debugger.Session}: methods {@link
org.netbeans.api.debugger.Session#lookup(String,Class)} and {@link
org.netbeans.api.debugger.Session#lookupFirst(String,Class)}
- {@link org.netbeans.api.debugger.DebuggerEngine}: methods {@link
org.netbeans.api.debugger.DebuggerEngine#lookup(String,Class)}, {@link
org.netbeans.api.debugger.DebuggerEngine#lookupFirst(String,Class)}, {@link
org.netbeans.api.debugger.DebuggerManager#lookup(String,Class)}
and {@link
org.netbeans.api.debugger.DebuggerManager#lookupFirst(String,Class)}
There are two ways how to registrer services. The first possibility is
to put 'live' instance of some service to the interface when a new
instance is created. This solution is supported by methods: {@link
org.netbeans.api.debugger.DebuggerInfo#create(String,Object[])}, {@link
org.netbeans.spi.debugger.SessionProvider#getServices()} and {@link
org.netbeans.spi.debugger.DebuggerEngineProvider#getServices()}. Second
possibility (and preferred one) is to register service to
Meta-inf/debugger folder. The way how to do it is described in Debugger
SPI documentation.
Debugger Start Process
The process which implements starting of debugger in Debugger Core
module is very simple. There is one instance of {@link
org.netbeans.api.debugger.DebuggerInfo} and {@link
org.netbeans.api.debugger.DebuggerManager#startDebugging(DebuggerInfo)}
method on the
begining of this process. DebuggerInfo determines a set of debugger
Sessions to be started:
List sessionProviders = debuggerInfo.lookup (null, SessionsProvider.class);
A new instance of {@link
org.netbeans.api.debugger.Session} is created for every {@link
org.netbeans.spi.debugger.SessionProvider} after that. A set of
DebuggerEngines is created for each Session in the second step:
List engineProviders = session.lookup (null, DebuggerEngineProvider.class);
Each {@link
org.netbeans.spi.debugger.DebuggerEngineProvider} drives creation of
one new instance of
{@link
org.netbeans.api.debugger.DebuggerEngine}. So, the debugger start
process creates a tree of
new Sessions and new DebuggerEngines and registers them to the
DebuggerManager.
Thats all.
Debugger Start
Process - advanced version
Debugger API supports two enhancements to the standard debugger start
process:
- Start new DebuggerEngine for already existing Session
- Create a new Session for already existing DebuggerEngine.
{@link
org.netbeans.spi.debugger.DelegatingSessionProvider} interface is
designed to support first usecase. You should implement and register
this interface in Meta-inf/debugger, to delegate on some existing
Session.
Second usecase is supported by interface {@link
org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider}.
Debugger Actions - how does it work
debuggercore-ui module installs some basic set of standard debugger
actions to NetBeans toolbar and menu. Debugger actions
(javax.swing.Action) are private. Each action is represented by some
constant in {@link
org.netbeans.api.debugger.ActionsManager} (like {@link
org.netbeans.api.debugger.ActionsManager#ACTION_STEP_INTO}).
ActionsManager manages list of registered {@link
org.netbeans.spi.debugger.ActionProvider}s. It contains mapping between
action constant and ActionProvider registerred for this constant. For
example:
instance
of DebuggerEngine which represents JPDA debugger contains mapping:
ActionsManager.ACTION_STEP_INTO
--> JPDAStepIntoActionProvider
How to implement and register some debugger action:
public class JPDAStepIntoAction extends ActionsProviderSupport {
JPDAStepIntoAction () { jpdaDebugger.add...Listener ( new Listener () { public ...event () { // set state of action here setEnabled ( state ); } } ); } public boolean doAction (Object action) { // put implementation of action here return true; // action successful } }
And JPDAStepIntoAction should be registerred in file:
META-INF/debugger/{DebuggerEngineTypeID}/org.netbeans.spi.debugger.ActionsProvider
Following two diagrams will show how the action system works:
Diagram 1 - what
happens when user press Step Into Action:
- StepIntoAction calls {@link
org.netbeans.api.debugger.ActionsManager#doAction(Object)} for {@link
org.netbeans.api.debugger.ActionsManager#ACTION_STEP_INTO}, when its
invoked by the user.
- {@link org.netbeans.api.debugger.ActionsManager} finds proper
{@link org.netbeans.spi.debugger.ActionsProvider} registered for given
action. Than it calls {@link
org.netbeans.spi.debugger.ActionsProvider#doAction(Object)}.
- {@link org.netbeans.api.debugger.ActionsManager} notifies all
{@link org.netbeans.api.debugger.ActionsManagerListener}s about it, when the
action is done.
user StepIntoAction DebuggerEngine StepIntoActionProvider DebuggerEngineListener (javax.swing.Action) | (ActionsProvider) | | | | | o press -> actionPerformed (...) | | | _|_ action calls | | | | button currentDebuggerEngine. --> doAction (ACTION_STEP_INTO) | | / \ doAction | | | (ACTION_STEP_INTO) finds ActionsProviders | | | registerred for given action --> doAction (ACTION_STEP_INTO) | | and calls doAction on them implementation of | | | Step Into Action is here | | | <-- | | | fires PROP_ACTION_PERFORMED | | | | --> -|-> actionPerformed (..) | | | listener impl. | <-- <-|- <-|- <--| | | | |
Diagram 2 - what
happens when the state of Step Into Action is changed:
- Debugger implementation should recognize that the state of Step
Into action should be changed, and it should notify
StepIntoActionProvider about it.
- StepIntoActionProvider should fire {@link
org.netbeans.spi.debugger.ActionsProviderListener#actionStateChange(Object,boolean)}
for {@link org.netbeans.api.debugger.ActionsManager#ACTION_STEP_INTO}.
- {@link org.netbeans.api.debugger.DebuggerEngine} is listenning on
all installed {@link org.netbeans.spi.debugger.ActionsProvider}s and
fires all action state changes using {@link
org.netbeans.api.debugger.DebuggerEngineListener#actionStateChanged(Object,boolean)}.
- StepIntoAction listens on {@link
org.netbeans.api.debugger.DebuggerEngine}, and it updates its state
when some actionStateChanged is fired.
debugger StepIntoActionProvider DebuggerEngine.ActionsProviderListener StepIntoAction.DebuggerEngineListener (ActionsProvider) | (javax.swing.Action) | | | _ state of -> fire action state | | |?| action change --> actionStateChange (ACTION_STEP_INTO, enabled) | ¯ should be | | | changed | fire DebuggerEngineListener | | actionStateChanged --> actionStateChanged | | updates a state | | of action |<-- <-|- <-- |
| org.netbeans.api.debugger.jpda |
package
JPDA Debugger APIs provide representation of JDI functionality. Interfaces in
org.netbeans.api.debugger.jpda package correspond to appropriate JDI interfaces.
Since JDI interfaces evolve from one version to another, it's strongly recommended
not to implement any interface in this package. New methods can be added to
these interfaces at any time to keep up with the JDI functionality.
| org.netbeans.api.debugger.jpda.event | | org.netbeans.examples.debugger.delegating | | org.netbeans.modules.ant.browsetask | | org.netbeans.modules.ant.debugger | | org.netbeans.modules.ant.debugger.breakpoints | | org.netbeans.modules.ant.freeform | | org.netbeans.modules.ant.freeform.spi | | org.netbeans.modules.ant.freeform.spi.support | | org.netbeans.modules.ant.freeform.ui | | org.netbeans.modules.ant.grammar |
Ant-XML Bridge Module
Ant Grammar Prototype
It is XML grammar plugin. Unfortunately the XML grammar
framework is not finalized so soft implementation
dependency is required (it's only a bridge).
Dependencies
XML dependencies are little bit hairy because:
- it needs an unfinalized API of XML Core module,
- at least one editor using the API must be enabled and
- such a editor does not require any grammar provider.
so it:
- depends on XML core module,
- still requires versioned token specifing explicit API version and
- requires unversioned API client token to avoid loading if no client enabled.
| org.netbeans.modules.debugger.delegatingview | | org.netbeans.modules.debugger.importd | | org.netbeans.modules.debugger.importd2 | | org.netbeans.spi.debugger |
package
The NetBeans Debugger SPI definition defines interface to Debugger
Plug-ins. It allows to extend some already existing debugger, or create
a new implementation of debugger.
Debugger SPI allows to:
- create a new instance of session: {@link
org.netbeans.spi.debugger.SessionProvider}, {@link
org.netbeans.spi.debugger.DelegatingSessionProvider}
- add support for a new language
to some Session: {@link
org.netbeans.spi.debugger.DebuggerEngineProvider}, {@link
org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider}
- install new watch evaluation engine: You can register a
new evaluator for watches - {@link
org.netbeans.spi.debugger.WatchesProvider} and {@link
org.netbeans.spi.debugger.WatchImpl}.
- add a new actions: A support for some new debugger action
(like Step Into Action) can be installed to some {@link
org.netbeans.api.debugger.DebuggerEngine} - {@link
org.netbeans.spi.debugger.ActionsProvider}, {@link
org.netbeans.spi.debugger.ActionsProviderSupport} and {@link
org.netbeans.spi.debugger.ActionsProviderListener}.
Registration
Debugger Core SPI contains service providers extending basic Debugger
Core API model. Each service provider must be registerred in
Meta-inf/debugger. Meta-inf/debugger is special folder in module *.jar
file.
If you would like to register some implementation(s) of some service to
some Debugger Core API interface of type {type name}, you should create
file with name {service full class name}in folder
Meta-inf/debugger/{type name}.
The file should contain a list of fully-qualified class names, one
per line, of classes implementing the service interface and having
default public constructor. It's also possible to append a name of
a static method followed by paranthesis, which returns the implementation
of the service. That method is then called instead of the default
constructor. The method can not take any arguments.
If there is a need to remove a service that is provided by some other
module, append '-hidden' after the class or method name. Space
and tab characters surrounding each name, as well as blank lines, are
ignored. The comment character is '#'
(\u0023 ); on each line all characters following the
first comment character are ignored. The file must be encoded in
UTF-8.
Example I:
I would like to register
org.netbeans.modules.debugger.jpda.actions.StepAction and
org.netbeans.modules.debugger.jpda.actions.StartAction service
implementations for JPDA DebuggerEngine. In this case I should create
file named org.netbeans.spi.debugger.ActionsProvider in folder
Meta-inf/debugger/netbeans-JPDADebuggerEngine/.
"netbeans-JPDADebuggerEngine" is a name of JPDA DebuggerEngine, and it
can be obtained from DebuggerEngine.getTypeID(). This file should
contain two lines:
org.netbeans.modules.debugger.jpda.actions.StepAction
org.netbeans.modules.debugger.jpda.actions.StartAction
Example II:
I would like to remove the default
'type' and 'toString' columns in LocalVariables view and add
a 'builtin' column instead. This is supposed to work for ANT debugger.
In this case I should create file named
org.netbeans.spi.viewmodel.ColumnModel in folder
META-INF/debugger/AntSession/LocalsView/.
This file should contain three lines, the first two remove columns we do
not want to appear for ANT debugger, the third adds ANT-specific
column:
org.netbeans.modules.debugger.ui.models.ColumnModels.createLocalsTypeColumn()-hidden
org.netbeans.modules.debugger.ui.models.ColumnModels.createLocalsToStringColumn()-hidden
org.netbeans.modules.ant.debugger.ColumnModels.createBuiltInColumn()
List of
all default service providers:
Service
provider interface
|
Should
be registerred to:
|
File
names:
|
{@link
org.netbeans.spi.debugger.SessionProvider}
|
{@link
org.netbeans.api.debugger.DebuggerInfo} |
folder name:
Meta-inf/debugger/{DebuggerInfo type name}
file name: org.netbeans.spi.debugger.SessionProvider
|
{@link
org.netbeans.spi.debugger.DelegatingSessionProvider} |
{@link
org.netbeans.api.debugger.DebuggerInfo} |
folder name:
Meta-inf/debugger/{DebuggerInfo type name}
file name: org.netbeans.spi.debugger.DelegatingSessionProvider |
{@link
org.netbeans.spi.debugger.DebuggerEngineProvider} |
{@link
org.netbeans.api.debugger.Session} |
folder name:
Meta-inf/debugger/{Session type name}
file name: org.netbeans.spi.debugger.DebuggerEngineProvider
|
{@link
org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider} |
{@link
org.netbeans.api.debugger.Session} |
folder name:
Meta-inf/debugger/{Session type name}
file name: org.netbeans.spi.debugger.DelegatingDebuggerEngineProvider |
{@link
org.netbeans.spi.debugger.WatchesProvider} |
{@link
org.netbeans.api.debugger.DebuggerEngine} |
folder name:
Meta-inf/debugger/{DebuggerEngine type name}
file name: org.netbeans.spi.debugger.WatchesProvider |
|
{@link
org.netbeans.spi.debugger.ActionsProvider}
|
{@link
org.netbeans.api.debugger.DebuggerEngine}
|
folder name:
Meta-inf/debugger/{DebuggerEngine type name}
file name: org.netbeans.spi.debugger.ActionsProvider |
|
| org.netbeans.spi.debugger.jpda |
package
JPDA Debugger SPIs defines support for Smart Stepping, Variables Filtering
and filtering of all Debugger Views.
Smart Stepping Support
Interfaces involved:
- {@link org.netbeans.api.debugger.jpda.SmartSteppingFilter} :
Defines list of class exclusion filters to be used to filter stepping
in debugged session.
- {@link org.netbeans.spi.debugger.jpda.SmartSteppingCallback} :
Listens on stepping engine and defines classes / places the debugger
can stop in.
- {@link org.netbeans.api.debugger.jpda.JPDAThread} : Represents
context for SmartSteppingCallback (class name, method name, line
number, ...).
Functionality supported:
Set of SmartSteppingCallback installed
to JPDA Debugger defines scope for Step Into / Over / Out Actions. When
user press some Step action, debugging is resumed. And when debugger
stops on some new place (defined by class name and line number) set of
SSListeners is asked if debugging should stop on this place or not (see
{@link org.netbeans.spi.debugger.jpda.SmartSteppingCallback#stopHere}
method). But this step-by-step method is slow. That is why the second,
more powerfull method is here. SSListener can define some set of class
exclusion patterns (like java.*, com.abba.Loader, ...). This set of
exclusion patterns managed by {@link
org.netbeans.api.debugger.jpda.SmartSteppingFilter} class defines scope
for Step Actions in more powerfull way.
JPDA Debugger installs one default SmartSteppingCallback. It excludes
all sourceless classes (packages). So, if user does not have mounted
sources for Java default libraries, this SSListener adds patterns like:
java.*, javax.* and com.sun.*.
How to implement some new Smart Stepping Listener:
Lets say we have some xxx module which
generates some code to standard Java classes. The generated code is
always in some methods, which name is prefixed with "xxx" like:
class MyClass { private void xxxBigBusinessMethod () { // generated code is here! } public void userMethod () { // user code is here... } }
And we would like to change standard
JPDA debugger to not stop in generated methods.
In this case we should implement {@link
org.netbeans.spi.debugger.jpda.SmartSteppingCallback}:
public class SmartSteppingCallbackImpl extends SmartSteppingCallback { public void initFilter (SmartSteppingFilter f) {} public boolean stopHere (JPDAThread thread, SmartSteppingFilter f) { String methodName = thread.getMethodName (); return !methodName.startsWith ("xxx"); // if method starts with "xxx" DO NOT stop there! } }
And register full class name of our implementation
(packagename.SmartSteppingCallback) in the file named:
META-INF\debugger\netbeans-JPDADebuggerEngine\org.netbeans.spi.debugger.jpda.SmartSteppingCallback
Variables Filtering
Support
Filtering of Debugger
Views
Content of all Debugger Views (like
Breakpoints View, Threads View, ...) can be changed by
viewmodel.*Filters. Folowing example shows how to filter Callstack
View. We would hide all frames associated with some "java.*" packages.
Some dummy node will be displayed in the place of this frames.
Step 1.
We should implement {@link
org.netbeans.spi.viewmodel.TreeModelFilter} first:
public class CallStackFilter implements TreeModelFilter { public Object[] getChildren (TreeModel original, Object parent, int from, int to) { Object[] originalCh = original.getChildren (parent, from, to); int i, k = originalCh.length; ArrayList newCh = new ArrayList (); boolean in = false; for (i = 0; i < k; i++) { if (! (originalCh [i] instanceof CallStackFrame)) { newCh.add (originalCh [i]);
continue; } CallStackFrame f = (CallStackFrame) originalCh [i]; String className = f.getClassName (); if (className.startsWith ("java")) { if (!in) { newCh.add (new JavaxSwing ()); in = true; } } else { in = false; newCh.add (f); } } return newCh.toArray (); } public Object getRoot (TreeModel original) { return original.getRoot (); } public boolean isLeaf (TreeModel original, Object node) throws UnknownTypeException { if (node instanceof JavaxSwing) return true; return original.isLeaf (node); } private static class JavaFrames {} }
And register it in file:
Meta-inf\debugger\netbeans-JPDADebuggerEngine\CallStackView\org.netbeans.spi.viewmodel.TreeModelFilter
As you can see on the picture this Filter replaces some original frames
by some dummy node.
Step 2.
We should provide NodeModel (at least)
for our new node type (JavaFrames) now.
public class CallStackFilter implements NodeModel {
public String getDisplayName (Object node) throws UnknownTypeException { if (node instanceof JavaFrames) return "Java Callstack Frames"; throw new UnknownTypeException (node); } public String getIconBase (Object node) throws UnknownTypeException { if (node instanceof JavaFrames) return "org/netbeans/examples/debugger/jpda/callstackviewfilterring/NonCurrentFrame"; throw new UnknownTypeException (node); } public String getShortDescription (Object node) throws UnknownTypeException { if (node instanceof JavaFrames) return "Unimportant hidden callstack frames"; throw new UnknownTypeException (node); } }
And registration:
Meta-inf\debugger\netbeans-JPDADebuggerEngine\CallStackView\org.netbeans.spi.viewmodel.TreeModelFilter
|
|