1 19 20 package org.netbeans.modules.apisupport.project; 21 22 import java.io.BufferedReader ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.InputStreamReader ; 26 import java.io.OutputStream ; 27 import java.io.OutputStreamWriter ; 28 import java.io.PrintWriter ; 29 import java.io.Reader ; 30 import java.net.URL ; 31 import java.util.ArrayList ; 32 import java.util.Arrays ; 33 import java.util.Collections ; 34 import java.util.HashMap ; 35 import java.util.Iterator ; 36 import java.util.List ; 37 import java.util.Map ; 38 import java.util.Set ; 39 import java.util.SortedSet ; 40 import java.util.TreeSet ; 41 import org.netbeans.api.project.Project; 42 import org.netbeans.api.project.ProjectManager; 43 import org.netbeans.modules.apisupport.project.layers.LayerUtils; 44 import org.netbeans.modules.apisupport.project.spi.NbModuleProvider; 45 import org.netbeans.spi.project.support.ant.EditableProperties; 46 import org.netbeans.spi.project.support.ant.PropertyUtils; 47 import org.openide.ErrorManager; 48 import org.openide.cookies.SaveCookie; 49 import org.openide.filesystems.FileLock; 50 import org.openide.filesystems.FileObject; 51 import org.openide.filesystems.FileSystem; 52 import org.openide.filesystems.FileUtil; 53 import org.openide.loaders.DataObject; 54 import org.openide.loaders.DataObjectNotFoundException; 55 import org.openide.modules.SpecificationVersion; 56 57 61 public final class CreatedModifiedFilesFactory { 62 63 static CreatedModifiedFiles.Operation addLoaderSection( 64 Project project, String dataLoaderClass, String installBefore) { 65 return new AddLoaderSection(project, dataLoaderClass, installBefore); 66 } 67 68 static CreatedModifiedFiles.Operation addLookupRegistration( 69 Project project, String interfaceClass, String implClass, boolean inTests) { 70 return new AddLookupRegistration(project, interfaceClass, implClass, inTests); 71 } 72 73 static CreatedModifiedFiles.Operation addModuleDependency(Project project, 74 String codeNameBase, String releaseVersion, SpecificationVersion version, boolean useInCompiler) { 75 return new AddModuleDependency(project, codeNameBase, releaseVersion, version, useInCompiler); 76 } 77 78 static CreatedModifiedFiles.Operation bundleKey(Project project, 79 String key, String value, String bundlePath) { 80 return new BundleKey(project, key, value, bundlePath); 81 } 82 83 static CreatedModifiedFiles.Operation bundleKeyDefaultBundle( 84 Project project, String key, String value) { 85 return new BundleKey(project, key, value); 86 } 87 88 static CreatedModifiedFiles.Operation createFile(Project project, 89 String path, URL content) { 90 return new CreateFile(project, path, content); 91 } 92 93 static CreatedModifiedFiles.Operation createFileWithSubstitutions(Project project, 94 String path, URL content, Map <String ,String > tokens) { 95 return new CreateFile(project, path, content, tokens); 96 } 97 98 static CreatedModifiedFiles.Operation layerModifications(Project project, CreatedModifiedFiles.LayerOperation op, Set <String > externalFiles, CreatedModifiedFiles cmf) { 99 return new LayerModifications(project, op, externalFiles, cmf); 100 } 101 102 static CreatedModifiedFiles.Operation createLayerEntry(CreatedModifiedFiles cmf, Project project, 103 String layerPath, URL content, 104 Map <String ,String > substitutionTokens, String localizedDisplayName, Map attrs) { 105 return new CreateLayerEntry(cmf, project, layerPath, content, 106 substitutionTokens, localizedDisplayName, attrs); 107 } 108 109 static CreatedModifiedFiles.Operation manifestModification(Project project, String section, 110 Map <String ,String > attributes) { 111 CreatedModifiedFilesFactory.ModifyManifest retval = 112 new CreatedModifiedFilesFactory.ModifyManifest(project); 113 for (Iterator it = attributes.entrySet().iterator(); it.hasNext();) { 114 Map.Entry entry = (Map.Entry ) it.next(); 115 String name = (String ) entry.getKey(); 116 String value = (String ) entry.getValue(); 117 retval.setAttribute(name, value, section); 118 } 119 return retval; 120 } 121 122 static CreatedModifiedFiles.Operation propertiesModification(Project project, 123 String propertyPath, Map <String ,String > properties) { 124 CreatedModifiedFilesFactory.ModifyProperties retval = 125 new CreatedModifiedFilesFactory.ModifyProperties(project, propertyPath); 126 for (Iterator it = properties.entrySet().iterator(); it.hasNext();) { 127 Map.Entry entry = (Map.Entry ) it.next(); 128 String name = (String ) entry.getKey(); 129 String value = (String ) entry.getValue(); 130 retval.setProperty(name, value); 131 } 132 return retval; 133 } 134 135 136 public static abstract class OperationBase implements CreatedModifiedFiles.Operation { 137 138 private Project project; 139 private SortedSet <String > createdPaths; 140 private SortedSet <String > modifiedPaths; 141 private SortedSet <String > invalidPaths; 142 143 protected OperationBase(Project project) { 144 this.project = project; 145 } 146 147 protected Project getProject() { 148 return project; 149 } 150 151 protected NbModuleProvider getModuleInfo() { 152 return getProject().getLookup().lookup(NbModuleProvider.class); 153 } 154 155 public String [] getModifiedPaths() { 156 String [] s = new String [getModifiedPathsSet().size()]; 157 return (String []) getModifiedPathsSet().toArray(s); 158 } 159 160 public String [] getCreatedPaths() { 161 String [] s = new String [getCreatedPathsSet().size()]; 162 return (String []) getCreatedPathsSet().toArray(s); 163 } 164 165 public String [] getInvalidPaths() { 166 String [] s = new String [getInvalidPathsSet().size()]; 167 return (String []) getInvalidPathsSet().toArray(s); 168 169 } 170 171 protected void addCreatedOrModifiedPath(String relPath, boolean allowFileModification) { 172 if (getProject().getProjectDirectory().getFileObject(relPath) == null) { 174 getCreatedPathsSet().add(relPath); 175 } else { 176 if (allowFileModification) { 177 getModifiedPathsSet().add(relPath); 178 } else { 179 getInvalidPathsSet().add(relPath); 180 } 181 } 182 } 183 184 protected void addPaths(CreatedModifiedFiles.Operation o) { 185 getCreatedPathsSet().addAll(Arrays.asList(o.getCreatedPaths())); 186 getModifiedPathsSet().addAll(Arrays.asList(o.getModifiedPaths())); 187 getInvalidPathsSet().addAll(Arrays.asList(o.getInvalidPaths())); 188 } 189 190 protected SortedSet <String > getCreatedPathsSet() { 191 if (createdPaths == null) { 192 createdPaths = new TreeSet (); 193 } 194 return createdPaths; 195 } 196 197 protected SortedSet <String > getInvalidPathsSet() { 198 if (invalidPaths == null) { 199 invalidPaths = new TreeSet (); 200 } 201 return invalidPaths; 202 } 203 204 protected SortedSet <String > getModifiedPathsSet() { 205 if (modifiedPaths == null) { 206 modifiedPaths = new TreeSet (); 207 } 208 return modifiedPaths; 209 } 210 211 protected boolean addCreatedFileObject(FileObject fo) { 212 return getCreatedPathsSet().add(getProjectPath(fo)); 213 } 214 215 protected boolean addModifiedFileObject(FileObject fo) { 216 return getModifiedPathsSet().add(getProjectPath(fo)); 217 } 218 219 223 private String getProjectPath(FileObject file) { 224 return PropertyUtils.relativizeFile( 225 FileUtil.toFile(getProject().getProjectDirectory()), 226 FileUtil.normalizeFile(FileUtil.toFile(file))); 227 } 228 229 } 230 231 private static final class CreateFile extends OperationBase { 232 233 private String path; 234 private URL content; 235 private Map <String ,String > tokens; 236 237 public CreateFile(Project project, String path, URL content) { 238 this(project, path, content, null); 239 } 240 241 public CreateFile(Project project, String path, URL content, Map <String ,String > tokens) { 242 super(project); 243 this.path = path; 244 this.content = content; 245 this.tokens = tokens; 246 addCreatedOrModifiedPath(path, false); 247 } 248 249 public void run() throws IOException { 250 FileObject targetFO = FileUtil.createData(getProject().getProjectDirectory(), path); 251 FileLock lock = targetFO.lock(); 252 try { 253 if (tokens == null) { 254 copyByteAfterByte(content, lock, targetFO); 255 } else { 256 copyAndSubstituteTokens(content, lock, targetFO, tokens); 257 } 258 } finally { 259 lock.releaseLock(); 260 } 261 } 262 263 } 264 265 private static void copyByteAfterByte(URL content, FileLock lock, FileObject targetFO) throws IOException { 266 OutputStream os = targetFO.getOutputStream(lock); 267 InputStream is = content.openStream(); 268 try { 269 FileUtil.copy(is, os); 270 } finally { 271 is.close(); 272 os.close(); 273 } 274 } 275 276 private static void copyAndSubstituteTokens(URL content, FileLock lock, FileObject targetFO, Map <String ,String > tokens) throws IOException { 277 boolean useUTF8 = targetFO.hasExt("xml"); OutputStream os = targetFO.getOutputStream(lock); 280 try { 281 PrintWriter pw; 282 if (useUTF8) { 283 pw = new PrintWriter (new OutputStreamWriter (os, "UTF-8")); } else { 285 pw = new PrintWriter (os); 286 } 287 try { 288 InputStream is = content.openStream(); 289 try { 290 Reader r; 291 if (useUTF8) { 292 r = new InputStreamReader (is, "UTF-8"); } else { 294 r = new InputStreamReader (is); 295 } 296 BufferedReader br = new BufferedReader (r); 297 String line; 298 while ((line = br.readLine()) != null) { 299 pw.println(tokens == null ? line : replaceTokens(tokens, line)); 300 } 301 } finally { 302 is.close(); 303 } 304 } finally { 305 pw.close(); 306 } 307 } finally { 308 os.close(); 309 } 310 } 311 312 private static String replaceTokens(Map <String ,String > tokens, String line) { 313 for (Iterator it = tokens.entrySet().iterator(); it.hasNext(); ) { 314 Map.Entry entry = (Map.Entry ) it.next(); 315 line = line.replaceAll((String ) entry.getKey(), (String ) entry.getValue()); 316 } 317 return line; 318 } 319 320 private static final class BundleKey extends OperationBase { 321 322 private final String bundlePath; 323 private final String key; 324 private final String value; 325 326 public BundleKey(Project project, String key, String value) { 327 this(project, key, value, null); 328 } 329 330 public BundleKey(Project project, String key, String value, String bundlePath) { 331 super(project); 332 this.key = key; 333 this.value = value; 334 if (bundlePath == null) { 335 336 ManifestManager mm = ManifestManager.getInstance(Util.getManifest(getModuleInfo().getManifestFile()), false); 337 String srcDir = getModuleInfo().getResourceDirectoryPath(false); 338 this.bundlePath = srcDir + "/" + mm.getLocalizingBundle(); } else { 340 this.bundlePath = bundlePath; 341 } 342 addCreatedOrModifiedPath(this.bundlePath, true); 343 } 344 345 public void run() throws IOException { 346 FileObject prjDir = getProject().getProjectDirectory(); 347 FileObject bundleFO = FileUtil.createData(prjDir, bundlePath); 348 EditableProperties ep = Util.loadProperties(bundleFO); 349 ep.setProperty(key, value); 350 Util.storeProperties(bundleFO, ep); 351 } 352 353 } 354 355 private static final class AddLoaderSection extends OperationBase { 356 357 private FileObject mfFO; 358 359 private String dataLoaderClass; 360 private String installBefore; 361 362 public AddLoaderSection(Project project, String dataLoaderClass, String installBefore) { 363 super(project); 364 this.dataLoaderClass = dataLoaderClass + ".class"; this.installBefore = installBefore; 366 this.mfFO = getModuleInfo().getManifestFile(); 367 addModifiedFileObject(mfFO); 368 } 369 370 public void run() throws IOException { 371 try { 374 DataObject dobj = DataObject.find(mfFO); 375 SaveCookie safe = (SaveCookie)dobj.getCookie(SaveCookie.class); 376 if (safe != null) { 377 safe.save(); 378 } 379 } catch (DataObjectNotFoundException ex) { 380 Util.err.notify(ErrorManager.WARNING, ex); 381 } 382 383 EditableManifest em = Util.loadManifest(mfFO); 384 em.addSection(dataLoaderClass); 385 em.setAttribute("OpenIDE-Module-Class", "Loader", dataLoaderClass); if (installBefore != null) { 387 em.setAttribute("Install-Before", installBefore, dataLoaderClass); } 389 Util.storeManifest(mfFO, em); 390 } 391 392 } 393 394 private static final class AddModuleDependency extends OperationBase { 395 396 private String codeNameBase; 397 private String releaseVersion; 398 private SpecificationVersion specVersion; 399 private boolean useInCompiler; 400 401 public AddModuleDependency(Project project, String codeNameBase, 402 String releaseVersion, SpecificationVersion specVersion, boolean useInCompiler) { 403 super(project); 404 this.codeNameBase = codeNameBase; 405 this.releaseVersion = releaseVersion; 406 this.specVersion = specVersion; 407 this.useInCompiler = useInCompiler; 408 getModifiedPathsSet().add(getModuleInfo().getProjectFilePath()); } 410 411 public void run() throws IOException { 412 getModuleInfo().addDependency(codeNameBase, releaseVersion, specVersion, useInCompiler); 413 ProjectManager.getDefault().saveProject(getProject()); 415 } 416 417 } 418 419 private static final class AddLookupRegistration extends OperationBase { 420 421 private String interfaceClassPath; 422 private String implClass; 423 424 public AddLookupRegistration(Project project, String interfaceClass, String implClass, boolean inTests) { 425 super(project); 426 this.implClass = implClass; 427 this.interfaceClassPath = getModuleInfo().getResourceDirectoryPath(inTests) + "/META-INF/services/" + interfaceClass; addCreatedOrModifiedPath(interfaceClassPath, true); 430 } 431 432 public void run() throws IOException { 433 FileObject service = FileUtil.createData( 434 getProject().getProjectDirectory(),interfaceClassPath); 435 436 String line = null; 437 List lines = new ArrayList (); 438 InputStream serviceIS = service.getInputStream(); 439 try { 440 BufferedReader br = new BufferedReader (new InputStreamReader (serviceIS, "UTF-8")); while ((line = br.readLine()) != null) { 442 lines.add(line); 443 } 444 } finally { 445 serviceIS.close(); 446 } 447 448 FileLock lock = service.lock(); 449 try { 450 PrintWriter pw = new PrintWriter (new OutputStreamWriter (service.getOutputStream(lock), "UTF-8")); try { 452 for (int i = 0; i < lines.size(); i++) { 453 line = (String ) lines.get(i); 454 if (i != lines.size() - 1 || !line.trim().equals("")) { 455 pw.println(line); 456 } 457 } 458 pw.println(implClass); 459 } finally { 460 pw.close(); 461 } 462 } finally { 463 lock.releaseLock(); 464 } 465 466 } 467 } 468 469 private static final class CreateLayerEntry extends OperationBase { 470 471 private CreatedModifiedFiles.Operation createBundleKey; 472 private CreatedModifiedFiles.Operation layerOp; 473 474 public CreateLayerEntry(CreatedModifiedFiles cmf, Project project, final String layerPath, 475 final URL content, 476 final Map <String ,String > tokens, final String localizedDisplayName, final Map attrs) { 477 478 super(project); 479 CreatedModifiedFiles.LayerOperation op = new CreatedModifiedFiles.LayerOperation() { 480 public void run(FileSystem layer) throws IOException { 481 FileObject targetFO = FileUtil.createData(layer.getRoot(), layerPath); 482 if (content != null) { 483 FileLock lock = targetFO.lock(); 484 try { 485 if (tokens == null) { 486 copyByteAfterByte(content, lock, targetFO); 487 } else { 488 copyAndSubstituteTokens(content, lock, targetFO, tokens); 489 } 490 } finally { 491 lock.releaseLock(); 492 } 493 } 494 if (localizedDisplayName != null) { 495 String bundlePath = ManifestManager.getInstance(Util.getManifest(getModuleInfo().getManifestFile()), false).getLocalizingBundle(); 496 String suffix = ".properties"; if (bundlePath != null && bundlePath.endsWith(suffix)) { 498 String name = bundlePath.substring(0, bundlePath.length() - suffix.length()).replace('/', '.'); 499 targetFO.setAttribute("SystemFileSystem.localizingBundle", name); } else { 501 } 503 } 504 if (attrs != null) { 505 Iterator it = attrs.entrySet().iterator(); 506 while (it.hasNext()) { 507 Map.Entry entry = (Map.Entry ) it.next(); 508 targetFO.setAttribute((String ) entry.getKey(), entry.getValue()); 509 } 510 } 511 } 512 }; 513 Set <String > externalFiles; 514 if (content != null) { 515 FileObject xml = LayerUtils.layerForProject(project).getLayerFile(); 516 FileObject parent = xml != null ? xml.getParent() : null; 517 externalFiles = Collections.singleton(LayerUtils.findGeneratedName(parent, layerPath)); 520 } else { 521 externalFiles = Collections.EMPTY_SET; 522 } 523 layerOp = new LayerModifications(project, op, externalFiles, cmf); 524 addPaths(layerOp); 525 if (localizedDisplayName != null) { 526 this.createBundleKey = new BundleKey(getProject(), layerPath, localizedDisplayName); 527 addPaths(this.createBundleKey); 528 } 529 } 530 531 public void run() throws IOException { 532 layerOp.run(); 533 if (createBundleKey != null) { 534 createBundleKey.run(); 535 } 536 } 537 } 538 539 private static final class LayerModifications implements CreatedModifiedFiles.Operation { 540 541 private final Project project; 542 private final CreatedModifiedFiles.LayerOperation op; 543 private final Set <String > externalFiles; 544 private final CreatedModifiedFiles cmf; 545 546 public LayerModifications(Project project, CreatedModifiedFiles.LayerOperation op, Set <String > externalFiles, CreatedModifiedFiles cmf) { 547 this.project = project; 548 this.op = op; 549 this.externalFiles = externalFiles; 550 this.cmf = cmf; 551 } 552 553 public void run() throws IOException { 554 op.run(cmf.getLayerHandle().layer(true)); 555 } 556 557 private String layerPrefix() { 558 FileObject layer = cmf.getLayerHandle().getLayerFile(); 559 if (layer == null) { 560 return null; 561 } 562 return FileUtil.getRelativePath(project.getProjectDirectory(), layer); 563 } 564 565 public String [] getModifiedPaths() { 566 String layerPath = layerPrefix(); 567 if (layerPath == null) { 568 return new String [0]; 569 } 570 return new String [] {layerPath}; 571 } 572 573 public String [] getCreatedPaths() { 574 String layerPath = layerPrefix(); 575 if (layerPath == null) { 576 return new String [0]; 577 } 578 int slash = layerPath.lastIndexOf('/'); 579 String prefix = layerPath.substring(0, slash + 1); 580 SortedSet s = new TreeSet (); 581 Iterator it = externalFiles.iterator(); 582 while (it.hasNext()) { 583 s.add(prefix + (String ) it.next()); 584 } 585 return (String []) s.toArray(new String [s.size()]); 586 } 587 588 public String [] getInvalidPaths() { 589 return new String [0]; 591 } 592 593 } 594 595 598 public static class ModifyManifest extends CreatedModifiedFilesFactory.OperationBase { 599 private FileObject manifestFile; 600 private Map attributesToAdd; 601 602 605 public ModifyManifest(final Project project) { 606 super(project); 607 this.attributesToAdd = new HashMap (); 608 addModifiedFileObject(getManifestFile()); 609 } 610 611 617 public final void setAttribute(final String name, final String value) { 618 setAttribute(name, value, "null"); } 620 621 628 public final void setAttribute(final String name, final String value, final String section) { 629 Map attribs = getAttributes(section); 630 if (attribs == null) { 631 attribs = new HashMap (); 632 attributesToAdd.put(section, attribs); 633 } 634 attribs.put(name, value); 635 } 636 637 645 protected void performModification(final EditableManifest em,final String name,final String value, 646 final String section) { 647 if (section != null && em.getSectionNames().contains(section)) { 648 em.addSection(section); 649 } 650 em.setAttribute(name, value, section); 651 } 652 653 public final void run() throws IOException { 654 ensureSavingFirst(); 655 656 EditableManifest em = Util.loadManifest(getManifestFile()); 657 for (Iterator sectionsIterator = attributesToAdd.keySet().iterator(); sectionsIterator.hasNext();) { 658 String section = (String ) sectionsIterator.next(); 659 Map attributes = getAttributes(section); 660 assert attributes != null; 661 662 for (Iterator attrsIterator = attributes.entrySet().iterator(); attrsIterator.hasNext();) { 663 Map.Entry entry = (Map.Entry ) attrsIterator.next(); 664 String name = (String ) entry.getKey(); 665 String value = (String ) entry.getValue(); 666 performModification(em, name, value, (("null".equals(section)) ? null : section)); } 668 } 669 670 Util.storeManifest(getManifestFile(), em); 671 } 672 673 674 private FileObject getManifestFile() { 675 if (manifestFile == null) { 676 manifestFile = getModuleInfo().getManifestFile(); 677 } 678 return manifestFile; 679 } 680 681 private Map getAttributes(final String sectionName) { 682 Map attribs = (Map )attributesToAdd.get(sectionName); 683 return attribs; 684 } 685 686 private void ensureSavingFirst() throws IOException { 687 try { 690 DataObject dobj = DataObject.find(getManifestFile()); 691 SaveCookie safe = (SaveCookie)dobj.getCookie(SaveCookie.class); 692 if (safe != null) { 693 safe.save(); 694 } 695 } catch (DataObjectNotFoundException ex) { 696 Util.err.notify(ErrorManager.WARNING, ex); 697 } 698 } 699 } 700 701 704 private static class ModifyProperties extends CreatedModifiedFilesFactory.OperationBase { 705 private Map properties; 706 private final String propertyPath; 707 private EditableProperties ep; 708 private FileObject propertiesFile; 709 710 private ModifyProperties(final Project project, final String propertyPath) { 711 super(project); 712 this.propertyPath= propertyPath; 713 addCreatedOrModifiedPath(propertyPath,true); 714 } 715 716 public void run() throws IOException { 717 EditableProperties ep = getEditableProperties(); 718 ep.putAll(getProperties()); 719 Util.storeProperties(getPropertyFile(),ep); 720 } 721 722 public final void setProperty(final String name, final String value) { 723 getProperties().put(name, value); 724 } 725 726 protected final FileObject getPropertyFile() throws IOException { 727 if (propertiesFile == null) { 728 FileObject projectDirectory = getProject().getProjectDirectory(); 729 propertiesFile = FileUtil.createData(projectDirectory, propertyPath); 730 } 731 return propertiesFile; 732 } 733 734 protected final EditableProperties getEditableProperties() throws IOException { 735 if (ep == null) { 736 ep = Util.loadProperties(getPropertyFile()); 737 } 738 return ep; 739 } 740 741 protected final Map getProperties() { 742 if (properties == null) { 743 this.properties = new HashMap (); 744 } 745 return properties; 746 } 747 } 748 } 749 750 | Popular Tags |