Hacking JRefactory
JRefactory is a large project, too much for one person to make rapid progress
in fixing bugs, adding features and supporting plugins for all the Java IDEs.
We need your help!
What needs to be done.
The JRefactory sourceforge project Feature Request page contains
a list of enhancements that have been requested. See also the requested feature page here.
Plugins for
- Eclipse - offer of support received.
- JDeveloper
- Netbeans
- JBuilder
- InteliJ
- Emacs JDE
There are lots more refactorings to be added, I reckon about 30 (including
those for generics and annotations).
Design patterns analyser/advisor
Objective - to be able to detect common design patterns (such as immutable
objects, factories, JavaBeans) and classes that nearly obey those patterns
(e.g. a class with only one mutator method).
Generate JavaDoc in the pretty-printer for the detected design patterns.
Advise on how to transform classes into those that obey the patterns,
including the possible refactoring required.
Common Code Detector
The cut and paste detector (inherited from PMD) does a good job of finding
cut and pasted sections of code. But it only works if the tokens are exactly
the same.
It would be nice to have a Common Code Detector that finds code segments
that are similar (but not identical).
For instance:
- code that is the same except for variable name changes.
- code that is the same except for a type change.
- code that is the same except for a difference in constant values.
Such common code segments are ripe for refactoring, especially within
a class or between classes in a heirarchy.
An added feature would be to create the refactoring required to eliminate
the common code.
profiling
JSR 163 - JavaTM Platform Profiling Architecture is defining a new
profiling architecture to replace JVMPI.
For refactoring it is useful to know where the hotspots in a program are.
The task would be to create a JPPA client to fit into JRefactory and use
it to mark classes and methods within the class diagram as regards to
processor usage and object creation. Starting and stopping the target
program profiling during a run would allow profiling during specific
sections of a targets operation. It would be great to include animation
of the class diagram (changing colours of the classe & method hotspots
as the target runs).
JSR 198
support and implement "A Standard Extension API for Integrated
Development Environments" when it becomes available.
Implementing a plugin
The main interface between the common code and the plugin is:
org.acm.seguin.ide.common.IDEInterface
all plugins should implement this interface, but not all of it needs to be
implemented for each of the components.
In general the jEdit plugin is the most advanced because that is the
one for which features are implemented first. So you should look there for
hints on how to implement a feature for other IDEs.
There are several concepts that should be implemented.
- IDE properties - there are some properties that should be read from
the IDE, for instance the plugin name. At present there is only one
property required "pmd.cpd.lastDirectory", but search for the method
getIDEProperty() to check the latest code.
- JRefactory Properties - these are obtained by the getProperties() method,
that takes as parameters a type string ("pretty", etc.) and the project (one
of the projects returned by getProjects(). The plugin should return a
org.acm.seguin.ide.common.options.PropertiesFile. The plugin may want to cache
this object for efficiency (see JavaStylePlugin.java). The saveProperties()
method tells the IDE to save all properties associated with JRefactory to
persistent storage.
- Projects - most IDEs have a concept of a "project", JRefactory stores
properties for each project, so that for-instance the pretty printer can
use formatting cusomised for each project. The method getProjects() should
return a list of projects the IDE currently knows about. The getProjectName()
method gets the project name for the buffer given as a parameter, in some IDEs
open buffers may not belong to the currently selected project.
- The wait cursor - an IDE will have a wait cursor which is shown during
long operations, showWaitCursor() and hideWaitCursor(), make it visible and
remove it respectively.
- Logging - JRefactory logs everything though one method log(). The plugin
should log this data to the IDE logging stream, filtering by the logging type:
DEBUG, MESSAGE, NOTICE, WARNING and ERROR.
- Buffer - a buffer is the IDE object that holds text being edited. The
common part of JRefractory treats buffers as transparent objects. There is
a current buffer (usually the one that has focus), and this may have its
text set by the setBuffer() method. this needs more work. An IDE
may have more than one buffer open. The goToBuffer() method should set the buffer
given as the parameter to have the focus.
- View - a view is the Frame holding the IDE. It is used a the parent frame
for dialogs within the common part of JRefactory. Some IDEs may have more than
one open Frame in which editing is taking place, this allows JRefactory to
distinguish between then.
- Selection - an area of text that has been highlighted and is selected by
the IDE for further processing. This may be set by setSelection()
- CPD - the cut and paste detector calls three methods cpdBuffer(),
cpdAllOpenBuffers() and cpdDir() to start the threads to perform the checks
on the current buffer, all open buffers or on a directory (possibly
recursively).
- Coding Standards Checking - similarly there are three methods the plugin
should implement for coding standards checking: checkBuffer(),
checkAllOpenBuffers() and checkDir().
- Line offsets - the two methods getStartLineOffset() and getEndLineOffset()
get offsets into a buffer for the given line. The Cursor may be moved to an
offset using moveCaretPosition().
- AWT Thread - the method runInAWTThread runs the runnable in the AWT thread
to allow things to be synchronized with the GUI. This does not call the awt
method directly to allow the IDE to manage the runnable.
- Buffer text - the complete text of a buffer should be obtained by
the getText() method. The getLineCount() method should get the number of lines for
a buffer.
- File for a buffer - each buffer is assumed to be editing a file, the
getFilePathForBuffer() method gets the full path of this file. The returned
path may be used by JRefactory in the openFile(). This method should open
the file into a buffer and set that buffer as the one having focus.
- Icons - loadIcon() should load an icon known to the IDE. At present the
only icon loaded in this way is "Clear.png" the icon for wiping the slate
clean. Plugins that call this icon by a different name may use a map to
convert it to the IDEs local name.
Note that at present there is an old singleton EditorOperations (and its subclasses)
that duplicates some of the IDEInterface. This will be removed and its functionality
merged with IDEInterface.
JavaStyle properties
The file src/ui/JavaStyle.props contains all the strings for the common part
of JRefactory.
Each plugin should have its own properties, the format of these is plugin
specific but see jEditFile/JavaStyle.props and other files in that directory
for how jEdit specific properties are implemented.
Specific properties for other IDEs should go in their own directory or in the
org.acm.seguin.ide.<IDE name> directory as appropriate for the IDE.
The manifest files for the IDE plugin should go in src/meta-inf.
The build file
The main build file is build.xml in the top level directory. It may be advisable
to have an IDE specific build file that is useable from within the IDE, often it
is easier to develop a plugin from within the IDE environment.
The build file should place built jar files int ant.build/lib/<IDE name>
and zip files containing the distribution in ant.build/dist.
In general the build.xml ant build file should have three targets per IDE:
- <IDE name>.JavaStyle.compile
- <IDE name>.JavaStyle.jar
- <IDE name>.JavaStyle.dist
which compile the plugin, create the jar file(s) and create the distribution
respectively.
Last Modified: 3 November 2003