当前页面:
在线文档首页 >
NetBeans API Javadoc (Current Development Version)
Overview (Refactoring API) - NetBeans API Javadoc (Current Development Version)
The Refactoring API module provides UI and API framework for easy and uniform implementation of refactoring features.
See:
Description
The Refactoring API module provides UI and API framework for easy and uniform implementation of refactoring features.
The Refactoring module provides:
- API, which allows clients to invoke refactorings programmatically.
- Plug-in SPI that allows other clients to participate in existing refactorings. E.g. Java Refactoring module implements refactoring features for java files,
while J2EE module adds refactoring capability for deployment descriptors
- API for definition of new Refactorings and pluging them into Refactoring framework
Use Cases
Refactoring module provides API for refactorings. The idea is that at least the most elementary set of refactorings should be
available via an API, so that the refactorings could be invoked programmatically. This is particulary useful when creating more
complex refactorings. These can then be composed from the primitive refactorings accessible via an API using delegation. As an example we can use
a simple rename refactoring. When renaming a class in a J2SE environment, simple rename refactoring (which renames all occurrences of
the class) is sufficient. However in a J2EE environment, renaming a class may require renaming of other classes to preserve the functionality
of the application (e.g. synchrinized renaming a home and remote interface for an EJB). This could be achieved by creating a more complex rename
refactoring composed of two simple rename refactorings (one for each class to be renamed).
When analyzing flow of various refactorings, we have found out that the steps in the flow are very common for all
refactorings. The flow is as follows:
- User selects an object (or set of objects) and chooses to invoke a particular refactoring on it.
- Refactoring pre-conditions are checked - whether a given refactoring can be invoked on a given object (or set of objects) or not. User needs to be
presented with errors (if any). The errors can be fatal or non-fatal. If an error is fatal, it means the refactoring cannot be performed, if it is not
fatal, user should be notified of the problem but still be able to proceed with the refactoring.
- User sets parameters of the refactoring - each refactoring has some input parameters (e.g. new name for an element in case of Rename refactoring).
These parameters need to be set by the client.
- Entered values of refactoring parameters are checked - errors (if any) are presented to the user.
- Refactoring collects all changes that need to be performed and presents them to the user.
- User can choose to not perform a particular set of proposed changes.
- Refactoring is performed - all the changes confirmed by user are made to the source code.
To make the implementation of various refactorings consistent, the refactoring module provides an API and UI framework that allows these refactorings to be plugged in. This
framework enforces the above flow. Using this framework (set of SPI and API) the refactoring implementor can focus purely on the things specific to that particular refactoring
(specific pre-conditions checks, parameters checks, implementation of changes, etc.) and leave the
functionality that is common for all refactorings (implementation of the flow) up to the framework.
It is quite common that some modules need to be able to affect the behavior of a refactoring. There are 4 typical use-cases when this is desirable:
- A module wants to implement refactoring features for their own elements. For instance Java Refactoring module wants to implement Refactoring for Java elements.
- A module wants to participate in existing refactoring. E.g. refactoring of java files requires refactoring of non-java files in J2EE area. When a code is refactored, these non-java files need to be refactored too.
We can mention JSP files or deployment descriptors as an example.
- A module introduces some hidden relationships between several elements. E.g. a single logical EJB consists of several physical classes. When one of these classes are refactored,
the other classes need to be refactored as well.
- A module generates some derived code into the guarded blocks. In such case it is desirable that the provider of the guarded block refactors the guarded code, since
the refactoring module itself has no knowledge of where the guarded code comes from.
The refactoring module provides hooks for other modules - an SPI that allows other modules to participate in refactorings. The modules can participate on all refactoring
phases from "preCheck" (checking preconditions), through "checkParameters" (checking validity of refactoring parameters) to "prepare" (collecting changes).
Use-cases number 1), 2) and 3) are covered by the same SPI (interfaces RefactoringPluginFactory and RefactoringPlugin). The forth use-case (guarded blocks) are covered by
a separate set of interfaces, since for this use-case the module does not need to participate in all refactoring phases. The refactoring framework itself automatically detects
that a given change points to a code in guarded blocks and requests all registered guarded block providers to handle that situation.
The rest of this section provides simple orientational examples of API/SPI usage.
Refactoring API can be used for programmatical invocation of refactorings and for pluging ui for these refactorings in.
Refactoring API Example:
Intention: Programatically rename java filecom/company/Test.java
to com/company/RenamedTest.java
and update references.
FileObject fo = ...com/company/Test.java...
RefactoringSession renameSession = RefactoringSession.create("Rename Class");
refactoring = new RenameRefactoring(fo);
Problem pre = refactoring.preCheck();
if (pre!=null && pre.isFatal()) {
//fatal problem in precheck
return;
}
refactoring.setNewName("RenamedTest");
Problem p = refactoring.prepare(renameSession);
if (p!=null && p.isFatal()) {
//fatal problem in precheck
return;
}
renameSession.doRefactoring(true /* saveAll */);
Refactoring SPI permit other modules to plug into existing refactorings and allow them to participate.
Client of SPI must implement factory class RefactoringPluginFactory
and register this class into Lookup.
Refactoring SPI Example 1:
Intention: Create a plugin for RenameRefactoring, which will participate in existing refactoring (let say in java refactoring)
and renames references in XML files.
//implementation of factory class
public class J2EERefactoringFactory implements RefactoringPluginFactory {
public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
if (refactoring instanceof RenameRefactoring) {
//return our custom instance for RenameRefactoring
if (wantToParticipate(refactoring.getRefactoredObject())
return new J2EERenameRefactoringPlugin((RenameRefactoring) refactoring);
}
if (refactoring instanceof ... {
...
}
return null;
}
}
It is necessary to register J2EERefactoringFactory
in the lookup:
META-INF/services/org.netbeans.modules.refactoring.spi.RefactoringPluginFactory
and implement RefactoringPlugin interface:
//implementation of RefactoringPlugin
public class J2EERenameRefactoringPlugin implements RefactoringPlugin {
private RenameRefactoring refactoring;
public J2EERenameRefactoringPlugin(RenameRefactoring refactoring) {
this.refactoring = refactoring;
}
public Problem preCheck() {
...
}
public Problem checkParameters() {
...
}
public Problem fastCheckParameters() {
...
}
public void cancelRequest() {
...
}
public Problem prepare(RefactoringElementsBag refactoringElements) {
RenameRefactoring renameRefactor = ((RenameRefactoring)refactoring);
Object element = renameRefactor.getRefactoredObject();
if (...) {
...
//lets add our RefactoringElements for usages found in XML files
refactoringElements.add(refactoring, new XMLRenameRefactoringElement());
}
return null;
}
public class XMLRenameRefactoringElement implements RefactoringElementImplementation {
public void performChange() {
//do change
}
}
Refactoring SPI Example 2:
Intention: Create a module, which will add Rename... to html files
First you must create your ActionsImplementationProvider:
public class MyProvider extends ActionsImplementationProvider {
public boolean canRename(Lookup lookup) {
Node[] nodes = lookup.lookupAll(Node.class);
if (..one node selected and the node belongs to html...)
return true;
else
return fals;
}
public Runnable renameImpl(Lookup selectedNodes) {
Node[] nodes = lookup.lookupAll(Node.class);
final FileObject fo = getFileFromNode(nodes[0]);
return new Runnable() {
public void run() {
UI.openRefactoringUI(new RenameRefactoringUI(fo);
}
}
}
}
And of course your own RefactoringPlugin and RefactoringPluginFactory see
Refactoring SPI Example 1 and
Refactoring SPI Example 2
Refactoring SPI Example 3
Module wants to implement it's own refactoring preview tree:
Register your own TreeElementFactoryImplementation into META-INF/services
if you want to build your own RefactoringPreview tree.
For instance Java Refactoring understand Java - specific objects e.g.
Projects, Groups, Methods etc.
public TreeElement getTreeElement(Object o) {
.
.
if (o instanceof SourceGroup) {
return new SourceGroupTreeElement((SourceGroup)o);
} else if (o instanceof SomethingFromJava) {
return new SomethingFromJavaTreeElement((SomethingFromJava) o);
}
TreeElement is then displayed in refactoring preview panel.
Other usecases are docummented in javadoc.
- Module wants to add common Refactoring Action into popup.
See RefactoringActionsFactory
-
http://wiki.netbeans.org/wiki/view/RefactoringFAQ
Exported Interfaces
This table lists all of the module exported APIs
with
defined stability classifications. It is generated
based on answers to questions about the architecture
of the module.
Read them all...
Group of java interfaces
Group of property interfaces
Interface Name | In/Out | Stability | Specified in What Document? |
|
Group of lookup interfaces
Interface Name | In/Out | Stability | Specified in What Document? |
org.netbeans.modules.refactoring.spi.RefactoringPluginFactory | Exported | Under Development | |
org.netbeans.modules.refactoring.spi.GuardedBlockHandlerFactory | Exported | Under Development | |
org.netbeans.modules.refactoring.spi.ReadOnlyFilesHandler | Exported | Under Development | |
org.netbeans.modules.refactoring.spi.ui.ActionsImplementationProvider | Exported | Under Development | |
org.netbeans.modules.refactoring.spi.ui.TreeElementFactoryImplementation | Exported | Under Development | |
|
Group of layer interfaces
Interface Name | In/Out | Stability | Specified in What Document? |
|
Implementation Details
Where are the sources for the module?
The sources for the module are in NetBeans
CVS in
refactoring/api
directory.
What do other modules need to do to declare a dependency on this one, in addition to or instead of a plain module dependency?
Nothing.
Read more about the implementation in the answers to
architecture questions.