Plugin API overview

# Plugins overview

- Plugin Files and Directories
- Plugin Loader
- AuditPlugin and MetricsPlugin Interfaces
- AuditPluginImpl and MetricsPluginImpl Abstract Classes
- Overloading of run Method
- Overloading Methods Processing Code Elements
- Overloading of Other Methods
- Useful PluginImpl Attributes
- Adding Results
- Options Pane Creation
- Creation of Description File
- Necessary Import Directives
- Samples and Source Code

## Plugin Files and Directories

All plugins are located in subdirectories of `com/togethersoft/modules/qa` directory. Audit plugins are located in the `audit` subdirectory while metrics plugins in `metrics` subdirectory.

Each plugin is located in its own directory and consists of at least three files: class file (or files), description file in html format and properties file.

Class file contains java class of plugin. Description file is displayed in description pane of the audit or metrics dialogue. Properties file stores plugin options.

Plugin's class name must be exactly the same as the name of its directory. Plugin's package name must be equal to `com.togethersoft.modules.qa.<subsystem>.<plugin_name>` ,where `<subsystem>` is `audit` for audit plugin and `metrics` for metrics plugin. Plugin description and properties file names must be the same as plugin class file name but with extension of "html" or "properties" accordingly.

## Plugin Loader

When metrics or audit system starts, plugin loader scans `metrics` or `audit` directory. It examines all its subdirectories. For each subdirectory, it tries to find file that have the same name as this subdirectory and "class" extension. If such file is found, plugin loader loads this class and creates its instance. Hence, plugin class must have public default constructor. Next, loader finds method with the signature `public void load()` in this class or its ancestors. If such method is found, plugin loader invokes it and then appends plugin to the plugins list. If any of the above-mentioned actions fails, plugin loader goes to the next subdirectory.

For each subsystem, audit, or metrics, this operation is performed only once, on the first invocation of subsystem.

## AuditPlugin and MetricsPlugin Interfaces

Each audit plugin must implement AuditPlugin interface. Each metrics plugin must implement MetricsPlugin interface (all mentioned classes belong to the package `com.togethersoft.modules.qa.api`).

These interfaces are both derived from `Plugin` interfaces.

The entry point of the `AuditPlugin` is `run` method. It is invoked for every package and class selected in diagram and for each subpackage and subclass. It examines class or package passed by parameter; if it discovers audit rule violation, it adds it to the violations list with the help of the static method `add` of AuditViolations class

`MetricsPlugin` entry point has the same name `run` but a different signature. It has two parameters. The first represents class or package. The second is an object of `MetricResult` class. Plugin stores the result value in this object.

## AuditPluginImpl and MetricsPluginImpl Abstract Classes

In theory, all you must do is to implement AuditPlugin or MetricsPlugin interface (depending on what kind of plugin, audit or metrics, you are developing). However, you rarely want to do it since it is much easier to derive your class from AuditPluginImpl or MetricsPluginImpl class. They both provide a set of convenient methods, going through the code of classes and packages and calling corresponding methods to process each package, class, method, expression and so on.

## Overloading of run Method

Overload run method. Its signature is
`public boolean run(SciObject obj)` for audit
and `public boolean run(SciObject obj, MetricsResult result)` for metrics plugin.

This method would be invoked for every package and class selected in diagram as well as for each their subpackage and subclass.

You can choose either of the following two ways to implement the run method. You can process object yourself, enumerating given SciObject attributes, operations and their code and so on via Together open API methods. Alternatively, you can make AuditPluginImpl to do all work for you and overload only methods processing entities, which are of interest for you (it might be only declaration statements and loops, for example). In this case, you run method simply call `PluginImpl.process` method. This method goes through the class attributes, operations, nested classes, their code and so on, and for each kind of above-mentioned class elements call corresponding methods ( `processAttrib` for each attribute, `processOper` for each operation, `processParam` for each operation parameter and so on.

The example of the first way you can see in the ExmMt1 and ExmMt2 samples. They both are interested only in counting of methods, so it is much more effective and even easier to enumerate class methods via Together open API methods.

ExmAu2 sample uses the second way. It must process all variable declarations, so it is better to delegate all work of going through methods and their code to PluginImpl in this case. Therefore, it calls `process` method of the superclass and overloads `processLoopStmt` and `processDeclStmt` methods. The first is called for each loop (for or while) statement while the second is called for each declaration.

To speed up the operation you may set `procGoal` variable to PROC_OPERS if you want PluginImpl to process only operations, or PROC_ATTRS if you are interested only in attributes, or both.

## Overloading Methods Processing Code Elements

When you call `PluginImpl.process` method, it examines whether the object passed by `obj` parameter represents a class (i.e. is instance of `SciClass` class). If so, `PluginImpl.processClass` method is invoked. This method goes through all class elements (attributes, methods, nested classes, code and so on) and invokes the following methods, which you can override.

`processAttrib` | for each attribute
`processLocalVar` | for each local variable
`processConceptVar` | for each attribute, parameter, or local variable
`processDeclStmt` | for each declaration statement
`processInitValue` | for each initialization expression of class attribute or local variable
`processCompStmt` | for each compound statement
`processCodeBlock` | for each code block
`processStatement` | for each statement within code block
`processExpression` | for each expression, including expressions in function calls, conditional or loop statements and so on
`processExprStmt` | for each expression statement
`processSwitchStmt` | for each switch statement
`processCaseStmt` | for each case statement
`processIfStmt` | for each if statement
`processLoopStmt` | for each loop statement
`processOper` | for each operation
`processParam` | for each parameter of the operation
`processReturnStmt` | for each return statement
`processThrowSpec` | for each exception in the operation throw list
`processThrowStmt` | for each throw statement
`processTryStmt` | for each try-catch statement
`processCatchStmt` | for each catch statement
The following two methods are invoked for each class:
`processAttribs` | to process class attributes. Default implementation calls `processAttrib` for each attribute.
`processOpers` | to process class operations. Default implementation calls `processOper` for each operation.

The most of these methods have default implementation. For example, `processOper` method calls `processParam` for each parameter of operation, `processThrowSpec` for each exception in the throw list of operation and `processCodeBlock` for the body of operation. So, don't forget to call superclass' method if you are interested in further processing of current element.

Below you can see sequence diagram of the PluginImpl.processClass method. Since this diagram is too complex, it is divided into three parts. PluginImpl.processClass method consists of 1) processing class' attributes and 2) processing class' operations Therefore the first part of diagram shows common schema without details, the second shows attributes processing, and the third - operations processing.
Common sequence diagram (without details)
Attributes processing sequence diagram
Operations processing sequence diagram

## Overloading of Other Methods

You must also override the following methods

`public String getTitle()` to return the title of plugin. It is used to display plugin in list

`public String getGroupName()` to set plugin group. You may either return your own group name or return the name of any existing group.

It is also useful to override `getDefaultChoice()` method. It determines whether plugin would be initially chosen or not.

For audit plugin, you often want to override `getDefaultSeverity()` method (default severity is `SEVERITY_NORMAL`).

Values returned by metrics plugin are not aggregated by default, so as a rule, you also have to override `getDefaultAggregation()` method.

## Useful PluginImpl Attributes

`protected SciMember CurrMbr` contains member being processes
`protected SciClass currCls` contains class being processed
`protected boolean stopIter` allows to stop processing (if you will set it to `true`)

## Adding Results

The following classes stores audit and metrics results.

`MetricsResult` class stores the result of metrics plugin.
`AuditViolation` class stores information about violation of audit plugin rules.
`AuditViolations` class maintains the list of all such violations. (In fact, the only methods of `AuditViolations` class we are interested in is method `add`).

For audit plugin, you can use static method of AuditViolations class
`add(AuditPlugin plugin, SciObject node, SciObject item)` or
`add(AuditPlugin plugin, SciObject node, SciObject item, String explanation)` to add found errors or warnings.

For metrics plugin, `run` method simply sets the `value` attribute of the second parameter.

## Options Pane Creation

If you want to give user an opportunity to choose any additional options, you have to override the following four methods (see the ExmMt2 example).

The `createOptionsPane` method is used to create panel (the descendant of JComponent) with additional options. It is called once, upon plugin loading.

The `getOptionsPane` method returns panel created earlier by createOptionsPane.

The `storeOptions` method is invoked when user presses 'Start' button. It stores options selected with user in class variables and in the properties file.

The `restoreOptions` method is used to restore options from the properties file.

## Creation of Description File

Create description file in html format. Give it the same name as plugin class file and place it in plugin directory.

## Necessary Import Directives

You need to add the following import directives in your plugin source code:

`import com.togethersoft.modules.qa.api.*;
import com.togethersoft.modules.qa.utils.*;
import com.togethersoft.openapi.sci.*;
import com.togethersoft.openapi.sci.enum.*;
`

## Samples and Source Code

There are three samples of plugins - one for audit and two for metric plugins.

Audit plugin sample, ExmAu1 , inspects all variables declaration and warns if the declaration is within loop statement (as such declarations lower performance).

The first metrics plugin example, ExmMt1 , simply counts the number of operations of a class.

The second metrics plugin example, ExmMt2 , does the same as ExmMt1, but it allows user to choose whether he wants to count only public operations, or private, protected or package, or any combination of them.

We also provide source code of PluginImpl, AuditPluginImpl and MetricsPluginImpl classes.