5.2 Design
As already introduced in chapter one, the goal of this research is to create a prototype for a tool, that lets developers refactor their software without „Copy-and-paste“. This fact has great influence on design decisions for DPT-tool. It is important to define a potential users of a refactoring-tool and then look at their expectations. The user can be separated into two groups:
1) A software developer, who would use refactorings in his daily work for:
- „cleaning up“ the code, making code more flexible, easily extendible.
- to increase the speed of implementation by use of „wizard“-futures of the tool ( e.g. „Implement“-transformation will create implementer-class for an interface)
2) An experts, who, for example, maintains a framework and could use refactoring for:
- restructuring of the software for upgrade, adding new features to the program.
- to create his own „monster“-refactorings, which can be reused in the future.
Usually programmers are very lazy and impatient users, they expect:
- Quick start-up procedure
If „start-up“ procedure takes too long (e.g. if programmer has to include all of the source-files into new project) developer will prefer to change code by hand rather then setup a project.
- Standard and intuitive user interface
The main goal for GUI is to keep the interaction with the user as short as possible. The user-interface should have the same layout for every transformation(e.g. Parameter-dialog), so that the developer won't lose time learning a new GUI. It is also important to show the developer no more information as needed to complete his task, otherwise he will get lost in all -options, -conditions, -possibilities of the tool.
5.2.1 Environment
The DPT-tool is programmed in Java(JDK-2.0) on a WinNT4.0 platform with JBuilder3.0 development environment. DPT uses Swing-classes for the GUI and ANTLR2.7 compiler-compiler for the creation of the syntax-parser and the symbol table parser. DPT - runs on Win95/98/NT or Linux/Unix.
The implementation of DPT-software was completed in 3 months.
The initial design of DPT allows transformations of C/C++ and Java programs. Additionally it can support high level transformations like C to C++ or C++ to Java. The current version (DPT 1.1) supports only Java to Java transformations. To support the transformations for different programming languages the parser and the generators should be switched to the language of the source code.
5.2.1.1
Generators
The DPT-tool does not generate any changes to the program. Transformation is the job of additional modules(generator-beans) which will be dynamically loaded(and executed) on user-request. If the user chooses a transformation, DPT will load a generator for this transformation, pass the symbol-table and file-table to the generator, and wait while the generator does its job. Following each implementation of a transformation is a java-bean that:
- displays for the user the symbol-table(navigation for the parameters-setting)
- gets transformation-parameters from user
- checks the parameters of the transformation
- creates code-changes
- notifies the object-manager about code changes.
Although generators could be used for different languages (e.g. copy/move an entity) they depend on (written for) concrete programming-language.
Example: Multiple inheritance is not allowed in Java.
C++ does not have class-interfaces.
Contrary to parsers, generators are not generated by compiler-compiler.
For more information about the implementation of generators(see section 5.2.2 Design)
5.2.1.2
Parsers
DPT parses the source code by use of an abstract parser which could be a Java or C/C++
parser. The current version uses a Java-parser. This parser generates a symbol-table that should offer the Symbol-table interface.The implementation of that interface is used by DPT and passed on the chosen generator to complete the transformation.
The source-code parser is a very important part for the refactoring-tool. It should resolve all references and create a symbol table of the project. Experience shows that in some cases a parser is not thorough enough to resolve all of the references correctly and
a language-interpreter is needed. The development of a language-interpreter is not a part of this research, so we decided to create a parser, which does its best, but without guarantee to resolve all symbols of the program. For the creation of the source code parser we used a compiler-compiler. There were three compiler-compilers freely available for the language Java: JavaCC, ANTLR, SabelCC.
We decided to use ANTLR because:
- it is free
- a debugger is freely available for ANTLR
- it has a good error report.
- the syntax of the grammar for ANTLR is easy to learn
- parsers created by ANTLR are understandable
- ANTLR can generate parsers for Java/C++
- ANTLR has many well described examples
Like generators, parsers are implemented as java-beans and can be used without DPT for other programs or as „stand alone“ java source parsers.
There are three parsers available in the DPT-software package:
- Syntax parser(Java grammar recognizer)
- Symbol-table parser(Symbol table generator)
- DPT-parser(Parser for reading configuration and initialization-files)
Different than Syntax/ Symbol-table parsers, the DPT-parser is not generated by compiler-compiler. For more information see section 5.2.3.
5.2.2 Design of the
transformation
The design of the transformation and the generator beans is the most interesting part of the DPT-tool. The design is based on the following considerations:
- The DPT-tool does not generate any changes; All of the code changes should be created by the current(chosen) transformation(=generator bean).
- Consequently, the setting of the transformation-parameters and precondition-check are also parts of the current generator-bean. This implies that the parameter-assistant must be a part of the bean, too.
- Every transformation should have the same(similar) GUI-Dialog for their parameter-assistant, although the parameters and preconditions of the transformations are different. This implies that GUI-dialog should be parametrized and this requires the implementation of the paramatrized GUI-component.
- DPT allows the creation of the composed transformations. A bunch of generator-beans which act like one transformation.
5.2.2.1
Design of the transformation-bean(generator):
1) Each implementation of a transformation is derived from abstract class
GenAbstract, which implements generator-bean interface GenBean.
The transformation-bean has to implement exactly three methods:
- Constructor, with the transformation-name and GUI-rule for the assistant.
- CheckParameter-Method, which checks the preconditions of the transformation
- Create-Method, which generates the changes to the source code.
-
2) Abstract class GenAbstract, implements generator-bean interface GenBean
and has all GUI-components, action-handlers and execution logic.
3) Interface GenBean is offered to the „outside“-world. (e.g. for DPT-tool).
(Figure 5.3 UML: Generator-beans)
Example: Transformation „New class“(from generator point of view):
DPT loads the java-class NewClass which implements the interface GenBean and calls the method „Execute“, and passes the symbol-table and file-table to this class.The „Execute“ method implemented in the class GenAbstract gets the GUI-rule of the NewClass and executes dialog „DlgBrowse“. Each time the user sets a parameter, the dialog notifies object GenAbstract, which checks the parameter with the method implemented in NewClass. If the check succeed, GenAbstract stores this parameter, gets the next GUI-rule from NewClass and re-init dialog „DlgBrowse“ with a new rule. If all of the parameters are set, „DlgBrowse“ displays „OK“-button. If the user clicks on the „OK“-button, dialog „DlgBrowse“ notifies the GenAbstract, which calls the „Create“-function implemented in NewClass .The NewClass creates changes, notifies the DPT-tool and exits. DPT-tool re-parses the project files. Then the task is completed.
5.2.2.2
Design of the transformation-catalog:
1) An instance of the class Catalog is a part of the DPT-object manager. Class Catalog is a class-loader, which loads and executes transformations(generator-beans). The class Catalog is also a factory of the object Transformation. This catalog is initialized with a init-file that contains the names of all generator-beans, which are belong to this particular catalog.
2) DPT deals with composed transformations. For this purpose DPT has an object Transformation, which is an implementation of the interface GenBean like other generator-beans described above. The object Transformation is designed as a vector-container for generator-beans. By calling an interface-method of the Transformation will call sequential this method in all generator-beans that are available in the vector. It takes the output-parameters from the current bean and passes these parameters on the next bean.
As result, the basic transformation is a vector with only one generator and the composed transformation is a vector of generators.
Example: Transformation „New class“(from DPT point of view):
DPT-Frame notifies DPT-ObjectManager, that the user wants to execute this transformation. ObjectManager calls up the method „Execute“ for the instance variable Catalog and passes on the transformation-name(“NewClass“). The object Catalog checks if the generator-bean is available(e.g. if „NewClass.class“ can be loaded). If not it looks up a composition-file(“NewClass.trf“).The „.trf“- file contains the description (names) of all generator-beans that are available in this transformation. If generator („NewClass.class“) or „.trf“-file is available the catalog creates the object Transformation and loads all of the generator-beans to this object.
(Figure 5.4 UML: Transformation catalog)
When Transformation-object is created, the catalog simply calls up the execute-method ( GenBean-interface) of the object Transformation and passes symbol-table and file-table as parameters. The object Transformation takes the first generator-bean from the vector and forwards the execute-method call to it.
5.2.3 Classes and Objects
The implementation of the DPT-tool can be described as the development of several nearly independent modules:
- Generators-beans that implement the transformations.
- Development of the symbol-table for a java-program.
- Parsers for language Java(1.1).
- Implementation of a file-table for a project.
- GUI-components for the tool
- Objects for management of the tool-components.
Some of these modules(implemented as java-beans) I have developed as „stand-alone“ programs (like parsers, file-table) and attached then to the project by using the interface-features of the language java. The defined interfaces between the modules allow the extension and the switching of the modules for the future releases of DPT-tool.
In this section I would like to introduce some implementation features of the DPT-tool.
5.2.3.1 DPT-Classes
Package „dpt“ contains the GUI-components of the DPT-tool.
(Figure
5.5 UML: Package DPT)
- Class AppDPT contains the main-function of DPT. It creates the FrameDPT
- Class FrameDPT is the main frame of the DPT(see section 5.4.3)
- Dialog DlgGoTo is the implementation of „GoToLine“- action.
- Dialog DlgProject browses the attributes of the DPT-Project (see section 5.4.3)
- Dialog DlgAbout browses information about DPT-tool
- Dialog DlgCompose shows the composition of the transformation (see 5.4.3.1)
Note: Dialogs DlgHelp and DlgBrowse are parts of the package „generators“
Package „dpt.object“ contains the managment-objects of the DPT-Project.
- Interface OMIF offers the access-methods of the object-management.
It contains such methods as Save- ,Open-, Close-, a DPT-project. OMIF is the
interface to the GUI-Components of the tool. (Currently DPT uses concrete class OMAll instead OMIF) Any object-manager which offers this interface can be used by DPT-tool. Or any GUI can use OMAll object-manager by accessing its interface.
- Abstract Class OMAbstract implements interfaces: OInterface, OMIF
The interface-OInterface extends interfaces FileTab and SymbTab. The purpose of OMAbstract is the delegation of the Symbol-table and File-table to the Object-manager of the DPT-tool. OInterface is used by generator-beans for the execution of the transformation. The OMIF (described above) is used by GUI-components of the DPT-Tool for the initialization, action handling and browsing of the project data.
- Class OMAll extends the class OMAbstract. It contains the implementation of the
interface OMIF, during class OMAbstract implements OInterface.
- Class Catalog manages all transactions with the generator-beans. It generates the
information about available transformations( catalog-tree), dynamically loads the
required beans to the Transformation. A Catalog acts also as a factory for the class Transformation, which is a collection of the generator- beans. Catalog maintains the composition-files for catalogs and transformations.
(Figure 5.6 UML: DPT-objects)
5.2.3.2 File table implementation
Package „dpt.filetab“ contains the implementation of
the file-table for DPT-Project.
- Interface FileTab offers the access-methods of the file-table.
Any file-table which offers this interface can be used by the DPT-tool. DPT can be attached to the development environment that already has a file-table.
- Abstract class FATAbstract implements FileTab-interface and contains some of
the default methods like copy-files, add/delete multiple files.
- Class FAT is an implementation of the
file-table. It extends the class FATAbstract
and implements FileTab methods which are not already implemented in class FATAbstract. The files are stored as a vector of FileDPT-objects. Class FAT maintains the path to the working directory and the initialization-file. It parses each file by syntax-parser before adding this file to the file-table.
- Class FileDPT. Because the DPT-Project can be placed in any directory of the file-
system, a file in the file-table know only its name and its original location. The location of the working-copy will be built dynamically by the file-table (filename + working directory)
- Class ExtendFileFilter implements file -info and -extensions for Open-dialogs
(Figure 5.7 UML: File table classes)
5.2.3.3 Symbol table implementation
Package „dpt.symbtab“ contains the implementation of
the Symbol-Table.
- Interface SymbTab offers access methods for the symbol table.
Benefits: Any symbol-table which offers this interface can be used by DPT-tool.
- Class SymbolTable implements interface SymbTab. This class will be passed on
the „symtab“-parser in order to fill the symbol table with data.
The following classes are used internally by the class SymbolTable:
- Interface Reportable is used as a handle to all symbols that can be reported.
Implementation of this interface reports location, name, sub-symbols of the symbol.
- Class Definition. Every java construct is stored in symbol table as Definition
- Class BlockDef is a wrapper for unnamed „{}“-block statement.
- Class PrimitiveDef is a definition of primitive type such as „int“, „long“
- Class LabelDef is a definition of a label(e.g. „break“, „switch“)
(Figure 5.8 UML: Symbol table classes)
- Interface TypedDef represents definitions that have a "type" associated with them.
- Class VariableDef defines a variable.
- Class ArrayDef is a definition of an array
- Class MethodDef is an implementation of a method-definition
- Class MiltiDef is used for such multidefinitions as „overloaded methods“
- Abstract class ScopedDef extends Definition.
It represents a symbol that provides a scope that contains other symbols.
- Abstract class HasImports extends ScopedDef.
It represents a symbol that can import packages.
- Class PackageDef is a definition of a java-package
- Class ClassDef defines a Class or Interface
- Class DummyClass holds temporarily the name of a class until it can be resolved
Supporting classes:
- Class Occurance implements an occurrence of an indentifier in a file.(Location)
- Class StringTable. Symbol-table stores each unique string in the StringTable.
- Class JavaVector extends Vector(provides lookup and type resolution methods)
- Class JavaStack extends Stack(provides lookup and type resolution methods)
- Class JavaHashtable extends the class Hashtable(provides lookup and type resolution methods)
5.2.3.4 Parser-beans
Package „parsers.symbtab“ contains the symbol table parser
- Interface JavaTokenTypes contains the definition of java-tokens.
- Class JavaLexer is a character-scanner(Lexer) for the language Java (1.1)
- Class JavaToken is used to relay information from the scanner to the parser.
- Class SymbTabParser is the implementation of the parser.
- Class Main is the test program for the symbol-table parser.
-
Package „parsers.syntax“ contains the syntax-parser for Java(1.1).
- Interface JavaTokenTypes contains the definition of java-tokens.
-Class JavaLexer is a character-scanner(Lexer) for the language Java (1.1)
-Class JavaParser is the implementation of the parser.
-Class Main is the test program for the syntax parser.
Package „parsers.tools“ contains the helper-parser for DPT-tool.
-Class DPT-Parser is a parser for configuration-files with many additional features
-Class MsgBox is the implementation of the Pop-Up Box.
-Class ItemD is the implementation of the dictionary item(Name=Value)
-Class Converter has a couple of useful conversion-methods(static)
5.2.3.5 Generators-beans
As already described in section 5.2.2.1, the transformation is implemented by generator -bean. Every implemented bean extends class GenAbstract, that implements the interface GenBean. Most of the implemented beans use the generator-class Gen to create the code-changes. The package „generators.beans“ contains all of the implemented transformation-generators described in chapter 4: „Design of refactoring-catalog.“ (see section 5.2.2.1)
The package „generators“ (see below) contains abstract generators and the implementation of the base functionality for a transformation-bean.
„DPT-Assistant“-GUI components:
- Interface RuleIF describes the GUI-initialization parameters for the components of
the dialog-DlgBrowse(= „DPT-Assistant“)
- Abstract class RuleAbstract default implementation of the interface RuleIF
- Dialog DlgBrowse is the implementaion of the Transformation-Assistant
- Control CTabBrowse implements one tab-page of the dialog DlgBrowse
- Class RuleTAB implements the initialization rule for the CTabBrowse component
- Control CPanBrowse implements the symbol-panel of the CTabBrowse
- Class RuleGUI implements initialization rule for CPanBrowse
- Dialog DlgHelp displays the information about the transformation
- PopUp MsgBox displays the transformation messages
Transformation-bean
components:
- Interface OInterface extends interfaces symbtab and filetab. Describes the interface which must be passed to the generator-bean in order to execute transformation.
- Interface GenBean the generator-bean interface to DPT-tool and to the dialog
DlgBrowse. The class GenBean is implemented by every transformation.
- Abstract class GenAbstract implements the interface GenBean and contains the base functionality of the generator-bean.(see section 5.2.2.1)
- Class OParameter implements a parameter for a transformation.
- Class Transformation implements GenBean and acts like an usual generator-
bean. This class contains a vector of transformations.(see section 5.2.2.1)
- Bean Browser is the example implementation of default class-browser bean
- Class Gen is the real generator. Generates changes to the source-code.
5.2.4 Source code management
DPT-philosophy: The source code management is accomplished by application and not by generator-beans, because only the application has knowledge and information about original or working- source location, state, volume and dependencies. DPT operates only on copy of original source, because this is a "clean way" to differentiate between source to be built/run and source to be transformed. (Note the difference: the source of the transformation-program must be always correct!)
1) Location of the source code
DPT has no requirements for the location of the program code. DPT-Tool can be installed in any directory and is independent from the location of the source code.
Problem: How DPT will find the source code of program which has to be transformed?
Solution: Let the user specify his source files. Via Add/remove-file dialog, DPT copies all necessary files to the „/src“ directory of the project. Real(original) file-location and the date are stored in fat.ini -file of the project. DPT works on copy of the source code (working code) FAT-Object(file-table) takes care of all operations with source files.
It is stored in fat.ini.File allocation table for DPT-project contains:
a) Absolute path to root (change via add / remove files) like: „C:/Projects/root/proj1“
b) Absolute path to Myproj2( static) like: “C:/Projects/root/DPT“
c) List of relative path to root + filename + date(/beans/src/sql.java 30.01.1998)
2) Working code always has to be correct(no syntax errors)
Problem: The working code and symbol table always have to be correct.
Solution: Only correct source will be added to the project.
- Action: Add/Remove file dialog:
Step 1: New source-file will be checked for the correct syntax by the syntax-parser
Step 2: If the new file is ok, the symbol-table will be updated by symbol-table parser
- Action: Open project / start transformation:
DPT-Tool verifies that the project-files are up to date, otherwise they will be updated
Step 1: All updated source-files will be checked for the correct syntax by syntax-parser
Step 2: If all updated files are ok, the symbol-table will updated by symbol-table parser
- Action: After Transformation
Step 1: Modified source-files will be checked for correct syntax with syntax-parser
Step 2: If they are fine, the symbol-table will updated by symbol-table parser
(Figure
5.9 Management of the project files)
3)Working code always has to be up to date(with source
code)
Problem: After the user changes the source code, DPT has to update its working code
Solution: fat.ini will store the date of the last change in the source code
Update: After opening project, before transformation, upon user request(synchronize). During the update procedure DPT checks files for correct syntax.(see section 5.2.1.2) All updated source-files will be checked for the correct syntax by the syntax-parser. If an error occurs, this problem will be shown to the user and the old version of file will be used(and marked in fat.ini) After each transformation the source code has to be updated.
Problem: DPT gives the user a chance to built source code after each transformation
Solution: DPT has a list of affected files which need to be copied to their original
locations. The user can always built his new code and test it’s functionality.
Update: After transformation, after "undo" / "redo" – Action
4) User have to be able to "undo" and "redo" the transformation
Problem: The user may be unhappy with the behavior of his program after the
transformation. DPT needs to give the user a chance to undo/ redo the transformation.
Solution: Temp-copy of files which was selected to be modified.
Note: This affects the modification of
existing source files!
Example:
File sql.java was chosen to be modified -> copy this file to sql.j1
(if exists to sql.j2) Transformation start->end, DPT will write new sql.java to original source location. User built his application, tried it and decided to "undo" the transformation -> In this case DPT will copy sql.java to sql.j1%(e.g. sql.j2%) for "redo" and then it will copy sql.j1(e.g. sql.j2) to sql.java back to it’s original source location.
sql.java(work)---> sql.j1%
sql.j1 -->sql.java(work)---> sql.java(org)