KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > refactoring > NbMoveRefactoringPlugin


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.apisupport.refactoring;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31 import java.util.jar.Attributes JavaDoc;
32 import java.util.jar.Manifest JavaDoc;
33 import java.util.regex.Pattern JavaDoc;
34 import org.netbeans.api.java.project.JavaProjectConstants;
35 import org.netbeans.api.project.FileOwnerQuery;
36 import org.netbeans.api.project.Project;
37 import org.netbeans.api.project.ProjectUtils;
38 import org.netbeans.api.project.SourceGroup;
39 import org.netbeans.api.project.Sources;
40 import org.netbeans.jmi.javamodel.JavaClass;
41 import org.netbeans.jmi.javamodel.Resource;
42 import org.netbeans.modules.apisupport.project.EditableManifest;
43 import org.netbeans.modules.apisupport.project.NbModuleProject;
44 import org.netbeans.modules.javacore.api.JavaModel;
45 import org.netbeans.modules.refactoring.api.AbstractRefactoring;
46 import org.netbeans.modules.refactoring.api.MoveClassRefactoring;
47 import org.netbeans.modules.refactoring.api.Problem;
48 import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
49 import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
50 import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
51 import org.openide.ErrorManager;
52 import org.openide.filesystems.FileLock;
53 import org.openide.filesystems.FileObject;
54 import org.openide.filesystems.FileUtil;
55 import org.openide.loaders.DataObject;
56 import org.openide.util.NbBundle;
57
58 /**
59  *
60  * @author Milos Kleint
61  */

62 public class NbMoveRefactoringPlugin implements RefactoringPlugin {
63     protected static ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.modules.apisupport.refactoring"); // NOI18N
64

65     /** This one is important creature - makes sure that cycles between plugins won't appear */
66     private static ThreadLocal JavaDoc semafor = new ThreadLocal JavaDoc();
67     
68     
69     private MoveClassRefactoring refactoring;
70     private Collection JavaDoc manifestRefactorings;
71     private boolean firstManifestRefactoring = true;
72     
73     private HashMap JavaDoc oldManifests; /** <NBModuleProject, EditableManifest> */
74     private EditableManifest targetManifest;
75     
76     /**
77      * Creates a new instance of NbRenameRefactoringPlugin
78      */

79     public NbMoveRefactoringPlugin(AbstractRefactoring refactoring) {
80         this.refactoring = (MoveClassRefactoring)refactoring;
81         
82         manifestRefactorings = new ArrayList JavaDoc();
83         oldManifests = new HashMap JavaDoc();
84     }
85     
86     /** Checks pre-conditions of the refactoring and returns problems.
87      * @return Problems found or null (if no problems were identified)
88      */

89     public Problem preCheck() {
90         return null;
91     }
92     
93     /** Checks parameters of the refactoring.
94      * @return Problems found or null (if no problems were identified)
95      */

96     public Problem checkParameters() {
97         return null;
98     }
99     
100     
101     public void cancelRequest() {
102         
103     }
104     
105     public Problem fastCheckParameters() {
106         return null;
107     }
108     
109     /** Collects refactoring elements for a given refactoring.
110      * @param refactoringElements Collection of refactoring elements - the implementation of this method
111      * should add refactoring elements to this collections. It should make no assumptions about the collection
112      * content.
113      * @return Problems found or null (if no problems were identified)
114      */

115     public Problem prepare(RefactoringElementsBag refactoringElements) {
116         if (semafor.get() != null) {
117             return null;
118         }
119         semafor.set(new Object JavaDoc());
120         try {
121             Problem problem = null;
122             Collection JavaDoc col = refactoring.getResources();
123             Project targetProject = FileOwnerQuery.getOwner(refactoring.getTargetClassPathRoot());
124             if (targetProject == null || ! (targetProject instanceof NbModuleProject)) {
125                 return problem;
126             }
127             NbModuleProject cachedProject = null;
128             String JavaDoc[] cachedServices = null;
129             FileObject[] cachedServicesFiles = null;
130             Manifest JavaDoc cachedManifest = null;
131             Iterator JavaDoc it = col.iterator();
132             while (it.hasNext()) {
133                 Resource res = (Resource)it.next();
134                 FileObject fo = JavaModel.getFileObject(res);
135                 Project project = FileOwnerQuery.getOwner(fo);
136                 if (project != null && project instanceof NbModuleProject) {
137                     if (cachedProject == null || cachedProject != project) {
138                         cachedProject = (NbModuleProject)project;
139                         cachedServices = loadMetaInfServices(cachedProject);
140                         cachedManifest = cachedProject.getManifest();
141                         FileObject services = Utility.findMetaInfServices(cachedProject);
142                         if (services == null) {
143                             cachedServicesFiles = new FileObject[0];
144                         } else {
145                             cachedServicesFiles = services.getChildren();
146                         }
147                     }
148                     String JavaDoc name = res.getName();
149                     String JavaDoc clazzName = name.replaceAll("\\.java$", ".class"); //NOI18N
150
String JavaDoc serviceName = name.replaceAll("\\.java$", "").replace('/', '.'); //NOI18N
151
JavaClass clazz = findClazz(res, serviceName);
152                     //check services for this one
153
for (int i = 0; i < cachedServices.length; i++) {
154                         serviceName = serviceName.replaceAll("[.]", "\\."); //NOI18N
155
// #65343 somehow the reading of individual services files can happen.
156
if (cachedServices[i] != null) {
157                             if (cachedServices[i].matches("^" + serviceName + "[ \\\n]?")) { //NOI18N
158
RefactoringElementImplementation elem =
159                                         new ServicesMoveRefactoringElement(clazz, cachedServicesFiles[i], cachedProject);
160                                 refactoringElements.add(refactoring, elem);
161                             }
162                         } else {
163                             //huh? reading the service file failed for some reason, report or silently ignore?
164
ErrorManager.getDefault().log(ErrorManager.WARNING, "Error loading one of the files in folder " + cachedServices);
165                         }
166                     }
167                     // check main attributes..
168
Attributes JavaDoc attrs = cachedManifest.getMainAttributes();
169                     Iterator JavaDoc itx = attrs.entrySet().iterator();
170                     while (itx.hasNext()) {
171                         Map.Entry JavaDoc entry = (Map.Entry JavaDoc)itx.next();
172                         String JavaDoc val = (String JavaDoc)entry.getValue();
173                         if (val.indexOf(clazzName) != -1 || val.indexOf(clazzName) != -1) {
174                             RefactoringElementImplementation elem =
175                                     createManifestRefactoring(clazz, cachedProject.getManifestFile(),
176                                     ((Attributes.Name JavaDoc)entry.getKey()).toString(), val, null, cachedProject);
177                             refactoringElements.add(refactoring, elem);
178                             manifestRefactorings.add(elem);
179                         }
180                     }
181                     // check section attributes
182
Map JavaDoc entries = cachedManifest.getEntries();
183                     if (entries != null) {
184                         Iterator JavaDoc itf = entries.entrySet().iterator();
185                         while (itf.hasNext()) {
186                             Map.Entry JavaDoc secEnt = (Map.Entry JavaDoc)itf.next();
187                             attrs = (Attributes JavaDoc)secEnt.getValue();
188                             String JavaDoc val = (String JavaDoc)secEnt.getKey();
189                             if (val.indexOf(clazzName) != -1) {
190                                 String JavaDoc section = attrs.getValue("OpenIDE-Module-Class"); //NOI18N
191
RefactoringElementImplementation elem =
192                                         createManifestRefactoring(clazz, cachedProject.getManifestFile(), null, val, section, cachedProject);
193                                 refactoringElements.add(refactoring, elem);
194                                 manifestRefactorings.add(elem);
195                             }
196                         }
197                     }
198                 }
199             }
200             // now check layer.xml and bundle file in manifest
201

202             Iterator JavaDoc itd = refactoring.getOtherDataObjects().iterator();
203             while (itd.hasNext()) {
204                 DataObject dobj = (DataObject)itd.next();
205                 Project project = FileOwnerQuery.getOwner(dobj.getPrimaryFile());
206                 if (project != null && project instanceof NbModuleProject) {
207                     if (cachedProject == null || cachedProject != project) {
208                         cachedProject = (NbModuleProject)project;
209                         cachedServices = loadMetaInfServices(cachedProject);
210                         cachedManifest = cachedProject.getManifest();
211                     }
212                 }
213                 String JavaDoc packageName = findPackageName(cachedProject, dobj.getPrimaryFile());
214                 if (packageName != null) {
215                     Iterator JavaDoc itf = cachedManifest.getMainAttributes().entrySet().iterator();
216                     while (itf.hasNext()) {
217                         Map.Entry JavaDoc ent = (Map.Entry JavaDoc)itf.next();
218                         String JavaDoc val = (String JavaDoc)ent.getValue();
219                         if (packageName.equals(val)) {
220                             RefactoringElementImplementation elem = new ManifestMoveRefactoringElement(cachedProject.getManifestFile(), val,
221                                     ((Attributes.Name JavaDoc)ent.getKey()).toString(), cachedProject, dobj.getPrimaryFile());
222                             refactoringElements.add(refactoring, elem);
223                             manifestRefactorings.add(elem);
224                         }
225                     }
226                 }
227             }
228             
229             return problem;
230         } finally {
231             semafor.set(null);
232         }
233     }
234     
235     protected RefactoringElementImplementation createManifestRefactoring(JavaClass clazz,
236             FileObject manifestFile,
237             String JavaDoc attributeKey,
238             String JavaDoc attributeValue,
239             String JavaDoc section, NbModuleProject proj) {
240         return new ManifestMoveRefactoringElement(clazz, manifestFile, attributeValue,
241                 attributeKey, section, proj);
242     }
243     
244     private JavaClass findClazz(Resource res, String JavaDoc name) {
245         Iterator JavaDoc itx = res.getClassifiers().iterator();
246         while (itx.hasNext()) {
247             JavaClass clzz = (JavaClass)itx.next();
248             if (clzz.getName().equals(name)) {
249                 return clzz;
250             }
251         }
252         //what to do now.. we should match always something, better to return wrong, than nothing?
253
return (JavaClass)res.getClassifiers().iterator().next();
254     }
255     
256     protected final String JavaDoc[] loadMetaInfServices(Project project) {
257         FileObject services = Utility.findMetaInfServices(project);
258         if (services == null) {
259             return new String JavaDoc[0];
260         }
261         
262         FileObject[] files = services.getChildren();
263         String JavaDoc[] ret = new String JavaDoc[files.length];
264         for (int i = 0; i < files.length; i++) {
265             ret[i] = Utility.readFileIntoString(files[i]);
266         }
267         return ret;
268     }
269     
270     private static String JavaDoc findPackageName(NbModuleProject project, FileObject fo) {
271         Sources srcs = ProjectUtils.getSources(project);
272         SourceGroup[] grps = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
273         for (int i = 0; i < grps.length; i++) {
274             if (FileUtil.isParentOf(grps[i].getRootFolder(), fo) && grps[i].contains(fo)) {
275                 return FileUtil.getRelativePath(grps[i].getRootFolder(), fo);
276             }
277         }
278         return null;
279     }
280     
281     
282     public final class ManifestMoveRefactoringElement extends AbstractRefactoringElement {
283         
284         private JavaClass clazz;
285         private String JavaDoc attrName;
286         private String JavaDoc sectionName = null;
287         private NbModuleProject project;
288         private FileObject movedFile = null;
289         public ManifestMoveRefactoringElement(JavaClass clazz, FileObject parentFile,
290                 String JavaDoc attributeValue, String JavaDoc attributeName,
291                 NbModuleProject project) {
292             this.name = attributeValue;
293             this.clazz = clazz;
294             this.parentFile = parentFile;
295             this.project = project;
296             attrName = attributeName;
297         }
298         public ManifestMoveRefactoringElement(JavaClass clazz, FileObject parentFile,
299                 String JavaDoc attributeValue, String JavaDoc attributeName, String JavaDoc secName,
300                 NbModuleProject project) {
301             this(clazz, parentFile, attributeValue, attributeName, project);
302             sectionName = secName;
303         }
304         
305         //for data objects that are not classes
306
public ManifestMoveRefactoringElement(FileObject parentFile,
307                 String JavaDoc attributeValue, String JavaDoc attributeName, NbModuleProject project, FileObject movedFile) {
308             this.name = attributeValue;
309             this.parentFile = parentFile;
310             attrName = attributeName;
311             this.project = project;
312             this.movedFile = movedFile;
313         }
314         
315         
316         
317         /** Returns text describing the refactoring formatted for display (using HTML tags).
318          * @return Formatted text.
319          */

320         public String JavaDoc getDisplayText() {
321             if (sectionName != null) {
322                 return NbBundle.getMessage(NbMoveRefactoringPlugin.class, "TXT_ManifestSectionRename", this.name, sectionName);
323             }
324             return NbBundle.getMessage(NbMoveRefactoringPlugin.class, "TXT_ManifestRename", this.name, attrName);
325         }
326         
327         public void performChange() {
328             NbModuleProject targetProject = (NbModuleProject)FileOwnerQuery.getOwner(refactoring.getTargetClassPathRoot());
329             if (firstManifestRefactoring) {
330                 // if this is the first manifest refactoring, check the list for non-enable ones and remove them
331
Iterator JavaDoc it = manifestRefactorings.iterator();
332                 while (it.hasNext()) {
333                     ManifestMoveRefactoringElement el = (ManifestMoveRefactoringElement)it.next();
334                     if (!el.isEnabled()) {
335                         it.remove();
336                     }
337                 }
338                 FileObject fo = targetProject.getManifestFile();
339                 targetManifest = readManifest(fo);
340                 firstManifestRefactoring = false;
341             }
342             
343             NbModuleProject sourceProject = project;
344             EditableManifest sourceManifest = null;
345             if (sourceProject == targetProject) {
346                 sourceManifest = targetManifest;
347             } else {
348                 sourceManifest = (EditableManifest)oldManifests.get(sourceProject);
349                 if (sourceManifest == null) {
350                     sourceManifest = readManifest(sourceProject.getManifestFile());
351                     oldManifests.put(sourceProject, sourceManifest);
352                 }
353             }
354             // update section info
355
if (sectionName != null) {
356                 String JavaDoc newSectionName = clazz.getName().replace('.', '/') + ".class"; //NOI18N
357
targetManifest.addSection(newSectionName);
358                 Iterator JavaDoc it = sourceManifest.getAttributeNames(name).iterator();
359                 while (it.hasNext()) {
360                     String JavaDoc secattrname = (String JavaDoc)it.next();
361                     targetManifest.setAttribute(secattrname, sourceManifest.getAttribute(secattrname, name), newSectionName);
362                 }
363                 sourceManifest.removeSection(name);
364             } else {
365                 // update regular attributes
366
if (sourceManifest != targetManifest) {
367                     sourceManifest.removeAttribute(attrName, null);
368                 }
369                 if (clazz != null) {
370                     String JavaDoc newClassname = clazz.getName().replace('.','/') + ".class"; //NOI18N
371
targetManifest.setAttribute(attrName, newClassname, null);
372                 } else {
373                     // mkleint - afaik this will get called only on folder rename.
374
String JavaDoc newPath = refactoring.getTargetPackageName(movedFile).replace('.','/') + "/" + movedFile.getNameExt(); //NOI18N
375
targetManifest.setAttribute(attrName, newPath, null);
376                 }
377             }
378             manifestRefactorings.remove(this);
379             if (manifestRefactorings.isEmpty()) {
380                 // now write all the manifests that were edited.
381
writeManifest(targetProject.getManifestFile(), targetManifest);
382                 Iterator JavaDoc it = oldManifests.entrySet().iterator();
383                 while (it.hasNext()) {
384                     Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
385                     EditableManifest man = (EditableManifest)entry.getValue();
386                     NbModuleProject proj = (NbModuleProject)entry.getKey();
387                     if (man == targetManifest) {
388                         continue;
389                     }
390                     writeManifest(proj.getManifestFile(), man);
391                 }
392             }
393         }
394     }
395     
396     public final class ServicesMoveRefactoringElement extends AbstractRefactoringElement {
397         
398         private JavaClass clazz;
399         private String JavaDoc oldName;
400         private NbModuleProject project;
401         /**
402          * Creates a new instance of ServicesRenameRefactoringElement
403          */

404         public ServicesMoveRefactoringElement(JavaClass clazz, FileObject file, NbModuleProject proj) {
405             this.name = clazz.getSimpleName();
406             parentFile = file;
407             this.clazz = clazz;
408             oldName = clazz.getName();
409             project = proj;
410         }
411         
412         /** Returns text describing the refactoring formatted for display (using HTML tags).
413          * @return Formatted text.
414          */

415         public String JavaDoc getDisplayText() {
416             return NbBundle.getMessage(NbMoveRefactoringPlugin.class, "TXT_ServicesRename", this.name);
417         }
418         
419         public void performChange() {
420             MoveClassRefactoring move = (MoveClassRefactoring)refactoring;
421             NbModuleProject newproject = (NbModuleProject)FileOwnerQuery.getOwner(move.getTargetClassPathRoot());
422             FileObject newFile = parentFile;
423             if (newproject != project) {
424                 FileObject services = Utility.findMetaInfServices(newproject);
425                 try {
426                     if (services == null) {
427                         services = createMetaInf(newproject);
428                     }
429                     newFile = services.getFileObject(parentFile.getNameExt());
430                     if (newFile == null) {
431                         newFile = services.createData(parentFile.getNameExt());
432                     }
433                 } catch (IOException JavaDoc ex) {
434                     err.notify(ex);
435                 }
436             }
437             String JavaDoc oldcontent = Utility.readFileIntoString(parentFile);
438             String JavaDoc longName = oldName;
439             String JavaDoc newName = clazz.getName();
440             if (oldcontent != null) {
441                 longName = longName.replaceAll("[.]", "\\."); //NOI18N
442
if (newFile == parentFile) {
443                     // same file, just replace
444
oldcontent = oldcontent.replaceAll("^" + longName, newName); //NOI18N
445
Utility.writeFileFromString(parentFile, oldcontent);
446                 } else {
447                     // moving to a different file.
448
oldcontent = oldcontent.replaceAll("^" + longName + "[ \\\n]?", ""); //NOI18N
449
String JavaDoc newcontent = Utility.readFileIntoString(newFile);
450                     newcontent = newName + "\n" + newcontent; // NOI18N
451
Utility.writeFileFromString(newFile, newcontent);
452                     //check if we want to delete the old file or just update it.
453
StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(oldcontent, "\n"); //NOI18N
454
boolean hasMoreThanComments = false;
455                     while (tok.hasMoreTokens()) {
456                         String JavaDoc token = tok.nextToken().trim();
457                         if (token.length() > 0 && (! Pattern.matches("^[#].*", token))) { //NOI18N
458
hasMoreThanComments = true;
459                             break;
460                         }
461                     }
462                     if (hasMoreThanComments) {
463                         Utility.writeFileFromString(parentFile, oldcontent);
464                     } else {
465                         try {
466                             parentFile.delete();
467                         } catch (IOException JavaDoc exc) {
468                             err.notify(exc);
469                         }
470                     }
471                     
472                 }
473             }
474         }
475     }
476     
477     private static FileObject createMetaInf(NbModuleProject project) throws IOException JavaDoc {
478         Sources srcs = ProjectUtils.getSources(project);
479         SourceGroup[] grps = srcs.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
480         for (int i = 0; i < grps.length; i++) {
481             FileObject fo = grps[i].getRootFolder().getFileObject("META-INF"); //NOI18N
482
if (fo != null) {
483                 return fo.createFolder("services"); //NOI18N
484
}
485         }
486         return grps[0].getRootFolder().createFolder("META-INF").createFolder("services"); //NOI18N
487
}
488     
489     private static EditableManifest readManifest(FileObject fo) {
490         InputStream JavaDoc str = null;
491         try {
492             str = fo.getInputStream();
493             return new EditableManifest(str);
494         } catch (IOException JavaDoc exc) {
495             err.notify(exc);
496         } finally {
497             if (str != null) {
498                 try {
499                     str.close();
500                 } catch (IOException JavaDoc exc) {
501                     err.notify(exc);
502                 }
503             }
504         }
505         return new EditableManifest();
506     }
507     
508     private static void writeManifest(FileObject fo, EditableManifest manifest) {
509         OutputStream JavaDoc str = null;
510         FileLock lock = null;
511         try {
512             lock = fo.lock();
513             str = fo.getOutputStream(lock);
514             manifest.write(str);
515             
516         } catch (IOException JavaDoc exc) {
517             err.notify(exc);
518         } finally {
519             if (str != null) {
520                 try {
521                     str.close();
522                 } catch (IOException JavaDoc exc) {
523                     err.notify(exc);
524                 }
525             }
526             if (lock != null) {
527                 lock.releaseLock();
528             }
529         }
530     }
531     
532 }
533
Popular Tags