|
|
|
|
Refactoring module allows developer to do high level code transformations aka refactorings.
Question (arch-overall): Describe the overall architecture. Answer: The Refactoring API module provides UI and API framework for easy and uniform implementation of refactoring features. The Refactoring module provides: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.
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 void doRename(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
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.
Target Milestone for this task is NetBeans 6.0Dev, M7
Question (arch-quality): How will the quality of your code be tested and how are future regressions going to be prevented? Answer:Refactoring module functionality will be covered by Refactoring Unit tests.
Question (arch-where): Where one can find sources for your module? Answer:
The sources for the module are in the Apache Git repositories or in the GitHub repositories.
None.
Question (dep-platform): On which platforms does your module run? Does it run in the same way on each? Answer:There are no known dependencies on any platform.
Question (dep-jre): Which version of JRE do you need (1.2, 1.3, 1.4, etc.)? Answer:Refactoring module doesn't have any special requirements on JDK version. It runs on JDK 1.5+
Question (dep-jrejdk): Do you require the JDK or is the JRE enough? Answer:JRE is enough.
We deploy only one file: module JAR.
Question (deploy-nbm): Can you deploy an NBM via the Update Center? Answer:Yes
Question (deploy-shared): Do you need to be installed in the shared location only, or in the user directory only, or can your module be installed anywhere? Answer:The module can be installed anywhere.
Question (deploy-packages): Are packages of your module made inaccessible by not declaring them public? Answer: The only public packages areYes
Question (compat-standards): Does the module implement or define any standards? Is the implementation exact or does it deviate somehow? Answer:Refactoring module exposes RefactoringAPI and RefactoringSPI
Question (compat-version): Can your module coexist with earlier and future versions of itself? Can you correctly read all old settings? Will future versions be able to read your current settings? Can you read or politely ignore settings stored by a future version? Answer:Refactoring module does not load or save any settings.
Question (compat-deprecation): How the introduction of your project influences functionality provided by previous version of the product? Answer:XXX no answer for compat-deprecation
java.io.File
directly?
Answer:
No
Question (resources-layer): Does your module provide own layer? Does it create any files or folders in it? What it is trying to communicate by that and with which components? Answer: Refactoring module registers following items:We read contents of Menu/Refactoring in order to provide the same popup menu.
Question (resources-mask): Does your module mask/hide/override any resources provided by other modules in their layers? Answer:We hide regular RenameAction (in Loaders/folder/any/Actions)
Question (resources-preferences): Does your module uses preferences via Preferences API? Does your module use NbPreferences or or regular JDK Preferences ? Does it read, write or both ? Does it share preferences with other modules ? If so, then why ? Answer:XXX no answer for resources-preferences
org.openide.util.Lookup
or any similar technology to find any components to communicate with? Which ones?
Answer:
Yes. We search for:
We register classes into META-INF/services:
org.openide.loaders.FolderRenameHandle to handle rename action on folders
org.openide.util.actions.ExtendedDelete to handle delete on multiple nodes
org.openide.util.datatransfer.ExClipboard$Convertor to register ClipboardConvertor
No
System.getProperty
) property?
On a similar note, is there something interesting that you
pass to java.util.logging.Logger
? Or do you observe
what others log?
Answer:
No
Question (exec-component): Is execution of your code influenced by any (string) property of any of your components? Answer:
ActionMapKeys
-
the usages window defines jumpNext
and jumpPrev
action
handlers in its ActionMap
.
XXX no answer for exec-ant-tasks
Question (exec-classloader): Does your code create its own class loader(s)? Answer:No.
Question (exec-reflection): Does your code use Java Reflection to execute other code? Answer:No
Question (exec-privateaccess): Are you aware of any other parts of the system calling some of your methods by reflection? Answer:No
Question (exec-process): Do you execute an external process from your module? How do you ensure that the result is the same on different platforms? Do you parse output? Do you depend on result code? Answer:No
Question (exec-introspection): Does your module use any kind of runtime type information (instanceof
,
work with java.lang.Class
, etc.)?
Answer:
Yes. Introspection is important part of Refactoring API. Refactoring API itself works in many cases just with "Objects" not knowing the type of object. API users are required to implement Refactorings only for objects, which are known to them.
Question (exec-threading): What threading models, if any, does your module adhere to? How the project behaves with respect to threading? Answer:Refactoring adhere threading model of java/source module.
Question (security-policy): Does your functionality require modifications to the standard policy file? Answer:No
Question (security-grant): Does your code grant additional rights to some other code? Answer:No
N/A
Question (format-dnd): Which protocols (if any) does your code understand during Drag & Drop? Answer:We don't override Node.drag. We have our own ClipboardConvertor. See above.
Question (format-clipboard): Which data flavors (if any) does your code read from or insert to the clipboard (by access to clipboard on means calling methods onjava.awt.datatransfer.Transferable
?
Answer:
We register our own ClipboardConvertor and we wrap each refactorable Node Transferables with Refactoring Transferables in order to handle move/cut/copy actions as refactoring actions.
No.
Question (perf-exit): Does your module run any code on exit? Answer:No
Question (perf-scale): Which external criteria influence the performance of your program (size of file in editor, number of files in menu, in source directory, etc.) and how well your code scales? Answer:Not known.
Question (perf-limit): Are there any hard-coded or practical limits in the number or size of elements your code can handle? Answer:No.
Question (perf-mem): How much memory does your component consume? Estimate with a relation to the number of windows, etc. Answer:I don't know.
Question (perf-wakeup): Does any piece of your code wake up periodically and do something even when the system is otherwise idle (no user interaction)? Answer:No
Question (perf-progress): Does your module execute any long-running tasks? Answer:Yes. Collecting usages is long-running task. It is properly indicated by progress bar and does not lock AWT thread.
Question (perf-huge_dialogs): Does your module contain any dialogs or wizards with a large number of GUI controls such as combo boxes, lists, trees, or text areas? Answer:Yes. RefactoringPanel (Output window with tree of found usages can contain big number of found references).
Question (perf-menus): Does your module use dynamically updated context menus, or context-sensitive actions with complicated and slow enablement logic? Answer:No
Question (perf-spi): How the performance of the plugged in code will be enforced? Answer:SPI will be well documented.