1 19 20 package org.netbeans.modules.apisupport.refactoring; 21 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.io.OutputStream ; 25 import java.util.ArrayList ; 26 import java.util.Collection ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.Map ; 30 import java.util.StringTokenizer ; 31 import java.util.jar.Attributes ; 32 import java.util.jar.Manifest ; 33 import java.util.regex.Pattern ; 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 62 public class NbMoveRefactoringPlugin implements RefactoringPlugin { 63 protected static ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.modules.apisupport.refactoring"); 65 66 private static ThreadLocal semafor = new ThreadLocal (); 67 68 69 private MoveClassRefactoring refactoring; 70 private Collection manifestRefactorings; 71 private boolean firstManifestRefactoring = true; 72 73 private HashMap oldManifests; 74 private EditableManifest targetManifest; 75 76 79 public NbMoveRefactoringPlugin(AbstractRefactoring refactoring) { 80 this.refactoring = (MoveClassRefactoring)refactoring; 81 82 manifestRefactorings = new ArrayList (); 83 oldManifests = new HashMap (); 84 } 85 86 89 public Problem preCheck() { 90 return null; 91 } 92 93 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 115 public Problem prepare(RefactoringElementsBag refactoringElements) { 116 if (semafor.get() != null) { 117 return null; 118 } 119 semafor.set(new Object ()); 120 try { 121 Problem problem = null; 122 Collection 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 [] cachedServices = null; 129 FileObject[] cachedServicesFiles = null; 130 Manifest cachedManifest = null; 131 Iterator 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 name = res.getName(); 149 String clazzName = name.replaceAll("\\.java$", ".class"); String serviceName = name.replaceAll("\\.java$", "").replace('/', '.'); JavaClass clazz = findClazz(res, serviceName); 152 for (int i = 0; i < cachedServices.length; i++) { 154 serviceName = serviceName.replaceAll("[.]", "\\."); if (cachedServices[i] != null) { 157 if (cachedServices[i].matches("^" + serviceName + "[ \\\n]?")) { RefactoringElementImplementation elem = 159 new ServicesMoveRefactoringElement(clazz, cachedServicesFiles[i], cachedProject); 160 refactoringElements.add(refactoring, elem); 161 } 162 } else { 163 ErrorManager.getDefault().log(ErrorManager.WARNING, "Error loading one of the files in folder " + cachedServices); 165 } 166 } 167 Attributes attrs = cachedManifest.getMainAttributes(); 169 Iterator itx = attrs.entrySet().iterator(); 170 while (itx.hasNext()) { 171 Map.Entry entry = (Map.Entry )itx.next(); 172 String val = (String )entry.getValue(); 173 if (val.indexOf(clazzName) != -1 || val.indexOf(clazzName) != -1) { 174 RefactoringElementImplementation elem = 175 createManifestRefactoring(clazz, cachedProject.getManifestFile(), 176 ((Attributes.Name )entry.getKey()).toString(), val, null, cachedProject); 177 refactoringElements.add(refactoring, elem); 178 manifestRefactorings.add(elem); 179 } 180 } 181 Map entries = cachedManifest.getEntries(); 183 if (entries != null) { 184 Iterator itf = entries.entrySet().iterator(); 185 while (itf.hasNext()) { 186 Map.Entry secEnt = (Map.Entry )itf.next(); 187 attrs = (Attributes )secEnt.getValue(); 188 String val = (String )secEnt.getKey(); 189 if (val.indexOf(clazzName) != -1) { 190 String section = attrs.getValue("OpenIDE-Module-Class"); 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 202 Iterator 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 packageName = findPackageName(cachedProject, dobj.getPrimaryFile()); 214 if (packageName != null) { 215 Iterator itf = cachedManifest.getMainAttributes().entrySet().iterator(); 216 while (itf.hasNext()) { 217 Map.Entry ent = (Map.Entry )itf.next(); 218 String val = (String )ent.getValue(); 219 if (packageName.equals(val)) { 220 RefactoringElementImplementation elem = new ManifestMoveRefactoringElement(cachedProject.getManifestFile(), val, 221 ((Attributes.Name )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 attributeKey, 238 String attributeValue, 239 String section, NbModuleProject proj) { 240 return new ManifestMoveRefactoringElement(clazz, manifestFile, attributeValue, 241 attributeKey, section, proj); 242 } 243 244 private JavaClass findClazz(Resource res, String name) { 245 Iterator 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 return (JavaClass)res.getClassifiers().iterator().next(); 254 } 255 256 protected final String [] loadMetaInfServices(Project project) { 257 FileObject services = Utility.findMetaInfServices(project); 258 if (services == null) { 259 return new String [0]; 260 } 261 262 FileObject[] files = services.getChildren(); 263 String [] ret = new String [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 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 attrName; 286 private String sectionName = null; 287 private NbModuleProject project; 288 private FileObject movedFile = null; 289 public ManifestMoveRefactoringElement(JavaClass clazz, FileObject parentFile, 290 String attributeValue, String 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 attributeValue, String attributeName, String secName, 300 NbModuleProject project) { 301 this(clazz, parentFile, attributeValue, attributeName, project); 302 sectionName = secName; 303 } 304 305 public ManifestMoveRefactoringElement(FileObject parentFile, 307 String attributeValue, String 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 320 public String 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 Iterator 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 if (sectionName != null) { 356 String newSectionName = clazz.getName().replace('.', '/') + ".class"; targetManifest.addSection(newSectionName); 358 Iterator it = sourceManifest.getAttributeNames(name).iterator(); 359 while (it.hasNext()) { 360 String secattrname = (String )it.next(); 361 targetManifest.setAttribute(secattrname, sourceManifest.getAttribute(secattrname, name), newSectionName); 362 } 363 sourceManifest.removeSection(name); 364 } else { 365 if (sourceManifest != targetManifest) { 367 sourceManifest.removeAttribute(attrName, null); 368 } 369 if (clazz != null) { 370 String newClassname = clazz.getName().replace('.','/') + ".class"; targetManifest.setAttribute(attrName, newClassname, null); 372 } else { 373 String newPath = refactoring.getTargetPackageName(movedFile).replace('.','/') + "/" + movedFile.getNameExt(); targetManifest.setAttribute(attrName, newPath, null); 376 } 377 } 378 manifestRefactorings.remove(this); 379 if (manifestRefactorings.isEmpty()) { 380 writeManifest(targetProject.getManifestFile(), targetManifest); 382 Iterator it = oldManifests.entrySet().iterator(); 383 while (it.hasNext()) { 384 Map.Entry entry = (Map.Entry )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 oldName; 400 private NbModuleProject project; 401 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 415 public String 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 ex) { 434 err.notify(ex); 435 } 436 } 437 String oldcontent = Utility.readFileIntoString(parentFile); 438 String longName = oldName; 439 String newName = clazz.getName(); 440 if (oldcontent != null) { 441 longName = longName.replaceAll("[.]", "\\."); if (newFile == parentFile) { 443 oldcontent = oldcontent.replaceAll("^" + longName, newName); Utility.writeFileFromString(parentFile, oldcontent); 446 } else { 447 oldcontent = oldcontent.replaceAll("^" + longName + "[ \\\n]?", ""); String newcontent = Utility.readFileIntoString(newFile); 450 newcontent = newName + "\n" + newcontent; Utility.writeFileFromString(newFile, newcontent); 452 StringTokenizer tok = new StringTokenizer (oldcontent, "\n"); boolean hasMoreThanComments = false; 455 while (tok.hasMoreTokens()) { 456 String token = tok.nextToken().trim(); 457 if (token.length() > 0 && (! Pattern.matches("^[#].*", token))) { hasMoreThanComments = true; 459 break; 460 } 461 } 462 if (hasMoreThanComments) { 463 Utility.writeFileFromString(parentFile, oldcontent); 464 } else { 465 try { 466 parentFile.delete(); 467 } catch (IOException exc) { 468 err.notify(exc); 469 } 470 } 471 472 } 473 } 474 } 475 } 476 477 private static FileObject createMetaInf(NbModuleProject project) throws IOException { 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"); if (fo != null) { 483 return fo.createFolder("services"); } 485 } 486 return grps[0].getRootFolder().createFolder("META-INF").createFolder("services"); } 488 489 private static EditableManifest readManifest(FileObject fo) { 490 InputStream str = null; 491 try { 492 str = fo.getInputStream(); 493 return new EditableManifest(str); 494 } catch (IOException exc) { 495 err.notify(exc); 496 } finally { 497 if (str != null) { 498 try { 499 str.close(); 500 } catch (IOException 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 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 exc) { 517 err.notify(exc); 518 } finally { 519 if (str != null) { 520 try { 521 str.close(); 522 } catch (IOException exc) { 523 err.notify(exc); 524 } 525 } 526 if (lock != null) { 527 lock.releaseLock(); 528 } 529 } 530 } 531 532 } 533 | Popular Tags |