Plugins overview

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.