In the Extending the Java Development Tools lecture you learned how the JDT works and how it builds upon the foundation of the Eclipse Platform. Most importantly, you learned how to reuse its framework and extend its user interface with your specific productivity enhancements. The solution presents several practical examples that demonstrate how you can implement such extensions.

1. How to analyze Java source code using ASTs and `ASTVisitor`. This simple Hello AST displays the structure of an AST. The ASTs are created from a hardcoded string representing a simple Java program and a user-provided Java source file.

2. How to extend the JDT user interface by adding a new view, specifically a Java Metrics view that shows the number of methods, fields, and literals within the selected `.java` source file. The view automatically updates when modifications are saved or new methods / fields are added.

3. How to extend the JDT user interface by adding new actions to the Java editor. The solution creates a new Add Trace Statements menu choice and toolbar button to analyze the source and insert trace statements that output the name and parameters of each method.

4. How to extend the JDT user interface by adding new actions to a Java element. Specifically, the solution creates a new Modifiers menu choice for the Java fields and methods, allowing the user to set them to public, default, protected, private, or final, directly from the Package Explorer, Outline view or Hierarchy view.

## Running the Solution

To run the example, launch the run-time instance of Eclipse (Run > Run As > Run-time Workbench).

1. Hello AST

   Select Soln: JDT Exercise > Run Hello AST. The output will be displayed to in the Console view of the development environment (not the run-time instance). After the initial output of the "Hello, World" AST is shown in the Console, it will then prompt for a Java source file in the Console. Look for the message "`Enter a fully qualified Java filespec:`" and enter a Java source file. For example:

   > `C:\eclipse2.0\eclipse\workspace\com.ibm.lab.soln.jdt\src-extension\com\ibm\lab\soln\jdt\HelloWorld.java`

   Don't choose a very large Java source file, the output will be very voluminous.

2. Java Metrics view

   Select Window > Show View > Java > Soln: Java Metrics to open, then select or open a Java source file. The metrics will update as you modify the source file.

3. Add Trace Statements

   Open a Java source file and select Soln: Add Trace Statements from the editor's context menu, or from the editor toolbar ().

4. Change `IMember` Modifiers

   Open a Java source file and select the Soln: Modifiers cascaded menu choice from method(s) or field(s) shown in the Package Explorer, Outline view, or Hierarchy view; choose one of the menu choices to modify the corresponding keyword: `public`, `default`, `protected`, `private`, or `final`.

## Roadmap of the Solution

As described above, this solution is partitioned into three parts, each covering a different part of the JDT and with increasing levels of complexity.

### Hello AST

This part of the solution will print the basic structure of a given AST to `System.out`. The idea is to get a quick tour of the `ASTVisitor` class and see how it helps you easily analyze Java code. As a bonus, this class is both instructive and helpful when debugging more complex ASTs.

As the name "Hello AST" suggests, this code will be primitive in its choice of input and output: `System.in` and `System.out`. This demonstrates the fact that the JDT model in the `org.eclipse.jdt.core` package, which defines the various Java elements, has no dependency on the JDT user interface package `org.eclipse.jdt.ui`.

Class (All) | Description
`ASTNode2StringVisitor` | This `ASTVisitor` subclass is responsible for processing instances of the Abstract Syntax Tree (AST), all subtypes of `ASTNode`. In this particular case, we want to visit all nodes, including their children, so it overrides the `preVisit(ASTNode)` method and prints it to `System.out`.
`HelloASTAction` | A contributed action to invoke the `ASTNode2StringVisitor` and display the content of an AST for two cases: A simple "Hello, World" Java source An arbitrary `.java` source file provided by the user.

### Java Metrics view

This view displays code metrics for the selected `.java` source file (an instance of `ICompilationUnit`). The Java Metrics view includes the number of methods, defined fields, and string literals. We could certainly add more metrics (e.g., hierarchy depth, number of imports, etc.), but the focus is on integrating with the JDT user interface and better familiarizing yourself with ASTs, so let's keeps it simple.

Class (All) | Description
`JavaMetrics` | Encapsulates the Java metrics for a given `ICompilationUnit`. The Java Metrics view creates a new JavaMetrics instance as its model when it opens.
`JavaMetricsAccumulator` | An inner class of `JavaMetrics`, this `ASTVisitor` subclass helps drive the metrics collection activity.
`IJavaMetricsListener` | Defines the interface between a `JavaMetrics` instance and those, like `JavaMetricsView`, who wish to be notified of its state changes
`JavaMetricsView` | View that displays the results of the `JavaMetrics` instance in simple text format. Listens for changes in its model and updates its display appropriately. Also listens for changes in the Workbench selection in order to set its model's `ICompilationUnit`.

You'll find that this solution contains a fair amount of code that you have already seen in prior solutions in one form or another. So the code commentary will focus on how to integrate with the JDT model with the help of an AST to produce a realistic and useful view.

### Add Trace Statements

Reusing the AST techniques shown in the prior two sections, this part of the solution contributes a new editor menu choice that adds trace statements to each method in a Java source file. The new concepts in this section are principally the workings of the Java editor itself, especially the "working copy" that all JDT editors use to stage modifications before committing them to the in-memory Java model.

There isn't much code and only two classes, but this solution introduces the notion of a compilation unit's working copy, and how to effect changes with its associated buffer.

Class (All) | Description
`AddTraceStatementsEditorActionDelegate` | Using the `JavaMethodsCollector` to get the method name and parameters of the editor's compilation unit, this action inserts trace statements based on them into the editor's working copy (a subclass of `CompilationUnit`), specifically by modifying its buffer content (an instance of `IBuffer`). The working copy's buffer content is what is displayed in an editor.
`JavaMethodsCollector` | Similar to our prior use of `JavaMetricsAccumulator`, this is an inner class of `AddTraceStatementsEditorActionDelegate` that defines an operation against an AST. It collects the compilation unit's method declarations (instances of `MethodDeclaration`, a subclass of `ASTNode`) that will be used to determine where the trace statements should be inserted in the source file and enumerate the parameters.

Note: The editor action, `AddTraceStatementsEditorActionDelegate`, is added in two contexts for demonstration purposes only. Realistically, you would likely choose one or the other (toolbar or pop-up menu) as the best place to add it. The "additions" location is the default, generally at the end of the toolbar or pop-up menu, and is sufficient for our purposes.

### Change `IMember` Modifiers

This part of the solution demonstrates object contributions to `IMember`, and how to use `IScanner` to perform fine-grain parsing.

Note: This solution is located in the `com.ibm.lab.soln.jdt.extras` package.

Class (All) | Description
`ChangeIMemberFlagAction` | This `Action` extension is responsible for adding/removing `IMember` modifiers. The other `MakeIMemberXxxAction` subclasses simply choose which flags must be removed and/or added to produce the desired results. For example, adding a `public` keyword requires that `private` or `protected` be removed, if present. Similarly, changing to default visibility requires that `public`, `protected`, or `private` keywords are removed (since there is no "default" keyword, meaning package-level visibility). By concentrating the mechanics of the substitutions in this class, its subclasses only have to define the "rules" for making the appropriate change.
`MakeIMemberDefaultAction` | Subclass of `ChangeIMemberFlagAction`, this action sets the `IMember`(s) modifiers to default.
`MakeIMemberPrivateAction` | Subclass of `ChangeIMemberFlagAction`, this action sets the `IMember`(s) modifiers to `private`.
`MakeIMemberProtectedAction` | Subclass of `ChangeIMemberFlagAction`, this action sets the `IMember`(s) modifiers to `protected`.
`MakeIMemberPublicAction` | Subclass of `ChangeIMemberFlagAction`, this action sets the `IMember`(s) modifiers to `public`.
`ToggleIMemberFinalAction` | Subclass of `ChangeIMemberFlagAction`, this action toggles the `IMember`(s) `final` modifiers.

© Copyright International Business Machines Corporation, 2003.
All rights reserved.