1 12 13 package org.eclipse.jdt.apt.core.internal.generatedfile; 14 15 import java.io.BufferedInputStream ; 16 import java.io.ByteArrayInputStream ; 17 import java.io.IOException ; 18 import java.io.InputStream ; 19 import java.util.ArrayList ; 20 import java.util.Collection ; 21 import java.util.HashMap ; 22 import java.util.HashSet ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import java.util.Map ; 26 import java.util.Set ; 27 import java.util.regex.Pattern ; 28 29 import org.eclipse.core.resources.IContainer; 30 import org.eclipse.core.resources.IFile; 31 import org.eclipse.core.resources.IFolder; 32 import org.eclipse.core.resources.IMarker; 33 import org.eclipse.core.resources.IResource; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.IPath; 36 import org.eclipse.core.runtime.IProgressMonitor; 37 import org.eclipse.jdt.apt.core.internal.AptPlugin; 38 import org.eclipse.jdt.apt.core.internal.AptProject; 39 import org.eclipse.jdt.apt.core.internal.Messages; 40 import org.eclipse.jdt.apt.core.internal.util.FileSystemUtil; 41 import org.eclipse.jdt.apt.core.internal.util.ManyToMany; 42 import org.eclipse.jdt.core.ElementChangedEvent; 43 import org.eclipse.jdt.core.ICompilationUnit; 44 import org.eclipse.jdt.core.IJavaModelStatusConstants; 45 import org.eclipse.jdt.core.IJavaProject; 46 import org.eclipse.jdt.core.IPackageFragment; 47 import org.eclipse.jdt.core.IPackageFragmentRoot; 48 import org.eclipse.jdt.core.JavaCore; 49 import org.eclipse.jdt.core.JavaModelException; 50 import org.eclipse.jdt.core.WorkingCopyOwner; 51 52 135 public class GeneratedFileManager 136 { 137 138 142 private class GeneratedPackageFragmentRoot { 143 144 final class NameAndRoot { 146 final String name; 147 final IPackageFragmentRoot root; 148 NameAndRoot(String name, IPackageFragmentRoot root) { 149 this.name = name; 150 this.root = root; 151 } 152 } 153 154 private IPackageFragmentRoot _root = null; 155 156 private String _folderName = null; 157 158 163 public synchronized NameAndRoot get() { 164 return new NameAndRoot(_folderName, _root); 165 } 166 167 172 public synchronized void set() { 173 IFolder genFolder = _gsfm.getFolder(); 174 _root = null; 175 if (_jProject.isOnClasspath(genFolder)) { 176 _root = _jProject.getPackageFragmentRoot(genFolder); 177 } 178 _folderName = genFolder.getProjectRelativePath().toString(); 179 } 180 } 181 182 188 private static final boolean RECURSIVE_RECONCILE = true; 189 190 195 private static final boolean GENERATE_TYPE_DURING_RECONCILE = true; 196 197 201 private static final boolean ENABLE_INTEGRITY_CHECKS = true; 202 203 206 private static final CompilationUnitHelper _CUHELPER = new CompilationUnitHelper(); 207 208 211 private static final Pattern _PACKAGE_DELIMITER = Pattern.compile("\\."); 213 static { 214 int mask = ElementChangedEvent.POST_CHANGE; 216 JavaCore.addElementChangedListener(new WorkingCopyCleanupListener(), mask); 217 } 218 219 224 private final GeneratedFileMap _buildDeps; 225 226 234 private final Set <IFile> _clearDuringReconcile; 235 236 242 private final ManyToMany<IFile, IFile> _reconcileDeps; 243 244 251 private final ManyToMany<IFile, IFile> _reconcileNonDeps; 252 253 272 private final Map <IFile, ICompilationUnit> _hiddenBuiltTypes; 273 274 293 private final Map <IFile, ICompilationUnit> _reconcileGenTypes; 294 295 299 private final GeneratedPackageFragmentRoot _generatedPackageFragmentRoot; 300 301 private final IJavaProject _jProject; 302 303 private final GeneratedSourceFolderManager _gsfm; 304 305 312 private boolean _skipTypeGeneration = false; 313 314 317 public GeneratedFileManager(final AptProject aptProject, final GeneratedSourceFolderManager gsfm) { 318 _jProject = aptProject.getJavaProject(); 319 _gsfm = gsfm; 320 _buildDeps = new GeneratedFileMap(_jProject.getProject()); 321 _clearDuringReconcile = new HashSet <IFile>(); 322 _reconcileDeps = new ManyToMany<IFile, IFile>(); 323 _reconcileNonDeps = new ManyToMany<IFile, IFile>(); 324 _hiddenBuiltTypes = new HashMap <IFile, ICompilationUnit>(); 325 _reconcileGenTypes = new HashMap <IFile, ICompilationUnit>(); 326 _generatedPackageFragmentRoot = new GeneratedPackageFragmentRoot(); 327 } 328 329 337 public void addGeneratedFileDependency(Collection <IFile> parentFiles, IFile generatedFile) 338 { 339 addBuiltFileToMaps(parentFiles, generatedFile, false); 340 } 341 342 345 public void compilationStarted() 346 { 347 try { 348 IMarker[] markers = _jProject.getProject().findMarkers(AptPlugin.APT_CONFIG_PROBLEM_MARKER, true, 350 IResource.DEPTH_INFINITE); 351 if (markers != null) { 352 for (IMarker marker : markers) 353 marker.delete(); 354 } 355 } catch (CoreException e) { 356 AptPlugin.log(e, "Unable to delete configuration marker."); } 358 _skipTypeGeneration = false; 359 _gsfm.ensureFolderExists(); 360 _generatedPackageFragmentRoot.set(); 361 362 } 363 364 368 public synchronized boolean containsWorkingCopyMapEntriesForParent(IFile f) 369 { 370 return _reconcileDeps.containsKey(f); 371 } 372 373 386 public Set <IFile> deleteObsoleteFilesAfterBuild(IFile parentFile, Set <IFile> newlyGeneratedFiles) 387 { 388 Set <IFile> deleted; 389 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(); 390 Set <IFile> toReport = new HashSet <IFile>(); 391 deleted = computeObsoleteFiles(parentFile, newlyGeneratedFiles, toDiscard, toReport); 392 393 for (IFile toDelete : deleted) { 394 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 395 "deleted obsolete file during build: " + toDelete); deletePhysicalFile(toDelete); 397 } 398 399 for (ICompilationUnit wcToDiscard : toDiscard) { 402 _CUHELPER.discardWorkingCopy(wcToDiscard); 403 } 404 405 return toReport; 406 } 407 408 426 public void deleteObsoleteTypesAfterReconcile(ICompilationUnit parentWC, Set <IFile> newlyGeneratedFiles) 427 { 428 IFile parentFile = (IFile) parentWC.getResource(); 429 430 List <ICompilationUnit> toSetBlank = new ArrayList <ICompilationUnit>(); 431 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(); 432 computeObsoleteReconcileTypes(parentFile, newlyGeneratedFiles, _CUHELPER, toSetBlank, toDiscard); 433 434 for (ICompilationUnit wcToDiscard : toDiscard) { 435 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 436 "discarded obsolete working copy during reconcile: " + wcToDiscard.getElementName()); _CUHELPER.discardWorkingCopy(wcToDiscard); 438 } 439 440 WorkingCopyOwner workingCopyOwner = parentWC.getOwner(); 441 for (ICompilationUnit wcToSetBlank : toSetBlank) { 442 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 443 "hiding file with blank working copy during reconcile: " + wcToSetBlank.getElementName()); _CUHELPER.updateWorkingCopyContents("", wcToSetBlank, workingCopyOwner, RECURSIVE_RECONCILE); } 446 447 assert checkIntegrity(); 448 } 449 450 458 public void fileDeleted(IFile f) 459 { 460 List <IFile> toDelete = removeFileFromBuildMaps(f); 461 462 for (IFile fileToDelete : toDelete) { 463 deletePhysicalFile(fileToDelete); 464 } 465 466 } 467 468 491 public FileGenerationResult generateFileDuringBuild(Collection <IFile> parentFiles, String typeName, String contents, 492 boolean clearDuringReconcile, IProgressMonitor progressMonitor) throws CoreException 493 { 494 if (_skipTypeGeneration) 495 return null; 496 497 GeneratedPackageFragmentRoot.NameAndRoot gpfr = _generatedPackageFragmentRoot.get(); 498 IPackageFragmentRoot root = gpfr.root; 499 if (root == null) { 500 String message = Messages.bind(Messages.GeneratedFileManager_missing_classpath_entry, 505 new String [] { gpfr.name }); 506 IMarker marker = _jProject.getProject().createMarker(AptPlugin.APT_CONFIG_PROBLEM_MARKER); 507 marker.setAttributes(new String [] { IMarker.MESSAGE, IMarker.SEVERITY }, new Object [] { message, 508 IMarker.SEVERITY_ERROR }); 509 _skipTypeGeneration = true; 511 return null; 512 } 513 514 IFile file = getIFileForTypeName(typeName); 517 boolean contentsDiffer = compareFileContents(contents, file); 518 519 try { 520 if (contentsDiffer) { 521 final String [] names = parseTypeName(typeName); 522 final String pkgName = names[0]; 523 final String cuName = names[1]; 524 525 IFolder genSrcFolder = (IFolder) root.getResource(); 527 final Set <IFolder> newFolders = computeNewPackageFolders(pkgName, genSrcFolder); 528 529 IPackageFragment pkgFrag = _CUHELPER.createPackageFragment(pkgName, root, progressMonitor); 531 532 for (IContainer folder : newFolders) { 534 try { 535 folder.setDerived(true); 536 } catch (CoreException e) { 537 AptPlugin.logWarning(e, "Unable to mark generated type folder as derived: " + folder.getName()); break; 539 } 540 } 541 542 saveCompilationUnit(pkgFrag, cuName, contents, progressMonitor); 543 } 544 545 addBuiltFileToMaps(parentFiles, file, true); 548 if (clearDuringReconcile) { 549 _clearDuringReconcile.add(file); 550 } 551 552 if (file.exists()) { 556 file.setDerived(true); 557 } 558 562 assert checkIntegrity(); 563 564 return new FileGenerationResult(file, contentsDiffer); 565 } catch (CoreException e) { 566 AptPlugin.log(e, "Unable to generate type " + typeName); return null; 568 } 569 } 570 571 590 public FileGenerationResult generateFileDuringReconcile(ICompilationUnit parentCompilationUnit, String typeName, 591 String contents) throws CoreException 592 { 593 if (!GENERATE_TYPE_DURING_RECONCILE) 594 return null; 595 596 IFile parentFile = (IFile) parentCompilationUnit.getResource(); 597 598 ICompilationUnit workingCopy = getWorkingCopyForReconcile(parentFile, typeName, _CUHELPER); 599 600 boolean modified = _CUHELPER.updateWorkingCopyContents( 602 contents, workingCopy, parentCompilationUnit.getOwner(), RECURSIVE_RECONCILE); 603 if (AptPlugin.DEBUG_GFM) { 604 if (modified) 605 AptPlugin.trace("working copy modified during reconcile: " + typeName); else 607 AptPlugin.trace("working copy unmodified during reconcile: " + typeName); } 609 610 IFile generatedFile = (IFile) workingCopy.getResource(); 611 return new FileGenerationResult(generatedFile, modified); 612 } 613 614 623 public synchronized Set <IFile> getGeneratedFilesForParent(IFile parent) 624 { 625 return _buildDeps.getValues(parent); 626 } 627 628 636 public synchronized boolean isGeneratedFile(IFile f) 637 { 638 return _buildDeps.containsValue(f); 639 } 640 641 642 643 654 public synchronized boolean isParentFile(IFile f) 655 { 656 return _buildDeps.containsKey(f); 657 } 658 659 662 public void projectCleaned() { 663 Iterable <ICompilationUnit> toDiscard = computeClean(); 664 for (ICompilationUnit wc : toDiscard) { 665 _CUHELPER.discardWorkingCopy(wc); 666 } 667 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 668 "cleared build file dependencies"); } 670 671 677 public void projectClosed() 678 { 679 if (AptPlugin.DEBUG_GFM) AptPlugin.trace("discarding working copy state"); List <ICompilationUnit> toDiscard; 681 toDiscard = computeProjectClosed(false); 682 for (ICompilationUnit wc : toDiscard) { 683 _CUHELPER.discardWorkingCopy(wc); 684 } 685 } 686 687 692 public void projectDeleted() 693 { 694 if (AptPlugin.DEBUG_GFM) AptPlugin.trace("discarding all state"); List <ICompilationUnit> toDiscard; 696 toDiscard = computeProjectClosed(true); 697 for (ICompilationUnit wc : toDiscard) { 698 _CUHELPER.discardWorkingCopy(wc); 699 } 700 } 701 702 705 public void reconcileStarted() 706 { 707 _generatedPackageFragmentRoot.set(); 708 } 709 710 718 public void workingCopyDiscarded(ICompilationUnit wc) throws CoreException 719 { 720 List <ICompilationUnit> toDiscard = removeFileFromReconcileMaps((IFile)(wc.getResource())); 721 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 722 "Working copy discarded: " + wc.getElementName() + " removing " + toDiscard.size() + " children"); for (ICompilationUnit obsoleteWC : toDiscard) { 725 _CUHELPER.discardWorkingCopy(obsoleteWC); 726 } 727 } 728 729 733 public void writeState() 734 { 735 _buildDeps.writeState(); 736 } 737 738 746 private synchronized void addBuiltFileToMaps(Collection <IFile> parentFiles, IFile generatedFile, boolean isSource) 747 { 748 for (IFile parentFile : parentFiles) { 751 if (parentFile != null) { 752 boolean added = _buildDeps.put(parentFile, generatedFile, isSource); 753 if (AptPlugin.DEBUG_GFM_MAPS) { 754 if (added) 755 AptPlugin.trace("build file dependency added: " + parentFile + " -> " + generatedFile); else 757 AptPlugin.trace("build file dependency already exists: " + parentFile + " -> " + generatedFile); } 759 } 760 } 761 } 762 763 767 private synchronized boolean checkIntegrity() throws IllegalStateException 768 { 769 if (!ENABLE_INTEGRITY_CHECKS || !AptPlugin.DEBUG_GFM_MAPS) { 770 return true; 771 } 772 773 Set <IFile> depChildren = _reconcileDeps.getValueSet(); Set <IFile> genTypes = _reconcileGenTypes.keySet(); List <IFile> extraFiles = new ArrayList <IFile>(); 778 for (IFile f : genTypes) { 779 if (!depChildren.remove(f)) { 780 extraFiles.add(f); 781 } 782 } 783 if (!extraFiles.isEmpty()) { 784 logExtraFiles("File(s) in reconcile-generated list but not in reconcile dependency map: ", extraFiles); 786 } 787 if (!depChildren.isEmpty()) { 788 logExtraFiles("File(s) in reconcile dependency map but not in reconcile-generated list: ", depChildren); 790 } 791 792 List <IFile> extraClearDuringReconcileFiles = new ArrayList <IFile>(); 794 for (IFile clearDuringReconcile : _clearDuringReconcile) { 795 if (!_buildDeps.containsValue(clearDuringReconcile)) { 796 extraClearDuringReconcileFiles.add(clearDuringReconcile); 797 } 798 } 799 if (!extraClearDuringReconcileFiles.isEmpty()) { 800 logExtraFiles("File(s) in list to clear during reconcile but not in build dependency map: ", extraClearDuringReconcileFiles); 802 } 803 804 List <IFile> extraHiddenTypes = new ArrayList <IFile>(); 806 for (IFile hidden : _hiddenBuiltTypes.keySet()) { 807 if (!_reconcileNonDeps.containsValue(hidden)) { 808 extraHiddenTypes.add(hidden); 809 } 810 } 811 if (!extraHiddenTypes.isEmpty()) { 812 logExtraFiles("File(s) in hidden types list but not in reconcile-obsoleted list: ", extraHiddenTypes); 814 } 815 816 Map <IFile, IFile> reconcileOverlaps = new HashMap <IFile, IFile>(); 819 for (IFile parent : _reconcileNonDeps.getKeySet()) { 820 for (IFile child : _reconcileNonDeps.getValues(parent)) { 821 if (_reconcileDeps.containsKeyValuePair(parent, child)) { 822 reconcileOverlaps.put(parent, child); 823 } 824 } 825 } 826 if (!reconcileOverlaps.isEmpty()) { 827 logExtraFilePairs("Entries exist in both reconcile map and reconcile-obsoleted maps: ", reconcileOverlaps); 829 } 830 831 Map <IFile, IFile> extraNonDeps = new HashMap <IFile, IFile>(); 834 for (IFile parent : _reconcileNonDeps.getKeySet()) { 835 for (IFile child : _reconcileNonDeps.getValues(parent)) { 836 if (!_buildDeps.containsKeyValuePair(parent, child)) { 837 extraNonDeps.put(parent, child); 838 } 839 } 840 } 841 if (!extraNonDeps.isEmpty()) { 842 logExtraFilePairs("Entries exist in reconcile-obsoleted map but not in build map: ", extraNonDeps); 844 } 845 846 List <IFile> nullHiddenTypes = new ArrayList <IFile>(); 848 for (Map.Entry <IFile, ICompilationUnit> entry : _hiddenBuiltTypes.entrySet()) { 849 if (entry.getValue() == null) { 850 nullHiddenTypes.add(entry.getKey()); 851 } 852 } 853 if (!nullHiddenTypes.isEmpty()) { 854 logExtraFiles("Null entries in hidden type list: ", nullHiddenTypes); } 856 857 List <IFile> nullReconcileTypes = new ArrayList <IFile>(); 859 for (Map.Entry <IFile, ICompilationUnit> entry : _reconcileGenTypes.entrySet()) { 860 if (entry.getValue() == null) { 861 nullReconcileTypes.add(entry.getKey()); 862 } 863 } 864 if (!nullReconcileTypes.isEmpty()) { 865 logExtraFiles("Null entries in reconcile type list: ", nullReconcileTypes); } 867 868 return true; 869 } 870 871 889 private synchronized List <ICompilationUnit> computeProjectClosed(boolean deleteState) 890 { 891 int size = _hiddenBuiltTypes.size() + _reconcileGenTypes.size(); 892 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(size); 893 toDiscard.addAll(_hiddenBuiltTypes.values()); 894 toDiscard.addAll(_reconcileGenTypes.values()); 895 _reconcileGenTypes.clear(); 896 _hiddenBuiltTypes.clear(); 897 _reconcileDeps.clear(); 898 _reconcileNonDeps.clear(); 899 900 if (deleteState) { 901 _buildDeps.clearState(); 902 } 903 else { 904 _buildDeps.clear(); 905 } 906 _clearDuringReconcile.clear(); 907 908 assert checkIntegrity(); 909 return toDiscard; 910 } 911 912 918 private boolean compareFileContents(String contents, IFile file) 919 { 920 boolean contentsDiffer = true; 921 if (file.exists()) { 922 InputStream oldData = null; 923 InputStream is = null; 924 try { 925 is = new ByteArrayInputStream (contents.getBytes()); 926 oldData = new BufferedInputStream (file.getContents()); 927 contentsDiffer = !FileSystemUtil.compareStreams(oldData, is); 928 } catch (CoreException ce) { 929 } finally { 931 if (oldData != null) { 932 try { 933 oldData.close(); 934 } catch (IOException ioe) { 935 } 936 } 937 if (is != null) { 938 try { 939 is.close(); 940 } catch (IOException ioe) { 941 } 942 } 943 } 944 } 945 return contentsDiffer; 946 } 947 948 961 private synchronized List <ICompilationUnit> computeClean() 962 { 963 _buildDeps.clearState(); 964 _clearDuringReconcile.clear(); 965 _reconcileNonDeps.clear(); 966 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(_hiddenBuiltTypes.values()); 967 _hiddenBuiltTypes.clear(); 968 969 assert checkIntegrity(); 970 return toDiscard; 971 } 972 973 981 private Set <IFolder> computeNewPackageFolders(String pkgName, IFolder parent) 982 { 983 Set <IFolder> newFolders = new HashSet <IFolder>(); 984 String [] folders = _PACKAGE_DELIMITER.split(pkgName); 985 for (String folderName : folders) { 986 final IFolder folder = parent.getFolder(folderName); 987 if (!folder.exists()) { 988 newFolders.add(folder); 989 } 990 parent = folder; 991 } 992 return newFolders; 993 } 994 995 1016 private synchronized Set <IFile> computeObsoleteFiles( 1017 IFile parentFile, Set <IFile> newlyGeneratedFiles, 1018 List <ICompilationUnit> toDiscard, 1019 Set <IFile> toReport) 1020 { 1021 Set <IFile> deleted = new HashSet <IFile>(); 1022 Set <IFile> obsoleteFiles = _buildDeps.getValues(parentFile); 1023 obsoleteFiles.removeAll(newlyGeneratedFiles); 1025 for (IFile generatedFile : obsoleteFiles) { 1026 boolean isSource = _buildDeps.isSource(generatedFile); 1027 _buildDeps.remove(parentFile, generatedFile); 1028 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 1029 "removed build file dependency: " + parentFile + " -> " + generatedFile); if (!_buildDeps.containsValue(generatedFile)) { 1032 deleted.add(generatedFile); 1033 if (isSource) { 1034 toReport.add(generatedFile); 1035 } 1036 } 1037 } 1038 _clearDuringReconcile.removeAll(deleted); 1039 toDiscard.addAll(computeObsoleteHiddenTypes(parentFile, deleted)); 1040 assert checkIntegrity(); 1041 return deleted; 1042 } 1043 1044 1067 private synchronized void computeObsoleteReconcileTypes( 1068 IFile parentFile, Set <IFile> newlyGeneratedFiles, 1069 CompilationUnitHelper cuh, 1070 List <ICompilationUnit> toSetBlank, List <ICompilationUnit> toDiscard) 1071 { 1072 Set <IFile> obsoleteFiles = _reconcileDeps.getValues(parentFile); 1074 Map <IFile, ICompilationUnit> typesToDiscard = new HashMap <IFile, ICompilationUnit>(); 1075 obsoleteFiles.removeAll(newlyGeneratedFiles); 1076 for (IFile obsoleteFile : obsoleteFiles) { 1077 _reconcileDeps.remove(parentFile, obsoleteFile); 1078 if (_reconcileDeps.getKeys(obsoleteFile).isEmpty()) { 1079 ICompilationUnit wc = _reconcileGenTypes.remove(obsoleteFile); 1080 assert wc != null : 1081 "Value in reconcile deps missing from reconcile type list: " + obsoleteFile; typesToDiscard.put(obsoleteFile, wc); 1083 } 1084 } 1085 1086 Set <IFile> builtChildren = _buildDeps.getValues(parentFile); 1087 builtChildren.retainAll(_clearDuringReconcile); 1088 builtChildren.removeAll(newlyGeneratedFiles); 1089 for (IFile builtChild : builtChildren) { 1090 _reconcileNonDeps.put(parentFile, builtChild); 1091 boolean foundOtherParent = false; 1094 Set <IFile> parents = _buildDeps.getKeys(builtChild); 1095 parents.remove(parentFile); 1096 for (IFile otherParent : parents) { 1097 if (!_reconcileNonDeps.containsKeyValuePair(otherParent, builtChild)) { 1098 foundOtherParent = true; 1099 break; 1100 } 1101 } 1102 if (!foundOtherParent) { 1103 ICompilationUnit wc = typesToDiscard.remove(builtChild); 1104 if (wc == null) { 1105 IPackageFragmentRoot root = _generatedPackageFragmentRoot.get().root; 1106 String typeName = getTypeNameForDerivedFile(builtChild); 1107 wc = cuh.getWorkingCopy(typeName, root); 1108 } 1109 _hiddenBuiltTypes.put(builtChild, wc); 1110 toSetBlank.add(wc); 1111 } 1112 } 1113 1114 toDiscard.addAll(typesToDiscard.values()); 1116 1117 assert checkIntegrity(); 1118 } 1119 1120 1138 private synchronized List <ICompilationUnit> computeObsoleteHiddenTypes(IFile parentFile, Set <IFile> deletedFiles) 1139 { 1140 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(); 1141 for (IFile deletedFile : deletedFiles) { 1142 if (_reconcileNonDeps.remove(parentFile, deletedFile)) { 1143 ICompilationUnit wc = _hiddenBuiltTypes.remove(deletedFile); 1144 if (wc != null) { 1145 toDiscard.add(wc); 1146 } 1147 } 1148 } 1149 assert checkIntegrity(); 1150 return toDiscard; 1151 } 1152 1153 1162 private void deletePhysicalFile(IFile file) 1163 { 1164 final IFolder genFolder = _gsfm.getFolder(); 1165 assert genFolder != null : "Generated folder == null"; IContainer parent = file.getParent(); try { 1169 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 1170 "delete physical file: " + file); file.delete(true, true, null); 1172 } catch (CoreException e) { 1173 AptPlugin.logWarning(e, "Unable to delete generated file: " + file); } 1176 while (!genFolder.equals(parent) && parent != null && parent.isDerived()) { 1178 IResource[] members = null; 1179 try { 1180 members = parent.members(); 1181 } catch (CoreException e) { 1182 AptPlugin.logWarning(e, "Unable to read contents of generated file folder " + parent); } 1184 IContainer grandParent = parent.getParent(); 1185 if (members == null || members.length == 0) 1187 try { 1188 parent.delete(true, null); 1189 } catch (CoreException e) { 1190 AptPlugin.logWarning(e, "Unable to delete generated file folder " + parent); } 1192 else 1193 break; 1194 parent = grandParent; 1195 } 1196 } 1197 1198 1204 private IFile getIFileForTypeName(String typeName) 1205 { 1206 String [] parts = _PACKAGE_DELIMITER.split(typeName); 1208 1209 IFolder folder = _gsfm.getFolder(); 1210 for (int i = 0; i < parts.length - 1; i++) 1211 folder = folder.getFolder(parts[i]); 1212 1213 String fileName = parts[parts.length - 1] + ".java"; IFile file = folder.getFile(fileName); 1216 return file; 1217 } 1218 1219 1224 private String getTypeNameForDerivedFile( IFile f ) 1225 { 1226 IPath p = f.getFullPath(); 1227 1228 IFolder folder = _gsfm.getFolder(); 1229 IPath generatedSourcePath = folder.getFullPath(); 1230 1231 int count = p.matchingFirstSegments( generatedSourcePath ); 1232 p = p.removeFirstSegments( count ); 1233 1234 String s = p.toPortableString(); 1235 int idx = s.lastIndexOf( '.' ); 1236 s = p.toPortableString().replace( '/', '.' ); 1237 return s.substring( 0, idx ); 1238 } 1239 1240 1254 private synchronized ICompilationUnit getWorkingCopyForReconcile(IFile parentFile, String typeName, CompilationUnitHelper cuh) 1255 { 1256 IPackageFragmentRoot root = _generatedPackageFragmentRoot.get().root; 1257 IFile generatedFile = getIFileForTypeName(typeName); 1258 ICompilationUnit workingCopy; 1259 1260 workingCopy = _hiddenBuiltTypes.remove(generatedFile); 1261 if (null != workingCopy) { 1262 _reconcileNonDeps.remove(parentFile, generatedFile); 1264 _reconcileGenTypes.put(generatedFile, workingCopy); 1265 _reconcileDeps.put(parentFile, generatedFile); 1266 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 1267 "moved working copy from hidden to regular list: " + generatedFile); } else { 1269 workingCopy = _reconcileGenTypes.get(generatedFile); 1270 if (null != workingCopy) { 1271 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 1272 "obtained existing working copy from regular list: " + generatedFile); } else { 1274 workingCopy = cuh.getWorkingCopy(typeName, root); 1276 _reconcileDeps.put(parentFile, generatedFile); 1277 _reconcileGenTypes.put(generatedFile, workingCopy); 1278 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 1279 "added new working copy to regular list: " + generatedFile); } 1281 } 1282 1283 assert checkIntegrity(); 1284 return workingCopy; 1285 } 1286 1287 1294 private boolean hasNoOtherReconcileParents(IFile child, IFile parent) { 1295 if (_reconcileDeps.valueHasOtherKeys(child, parent)) 1296 return true; 1297 Set <IFile> buildParents = _buildDeps.getKeys(child); 1298 buildParents.remove(parent); 1299 buildParents.removeAll(_reconcileNonDeps.getKeys(child)); 1300 return buildParents.isEmpty(); 1301 } 1302 1303 1307 private void logExtraFilePairs(String message, Map <IFile, IFile> pairs) { 1308 StringBuilder sb = new StringBuilder (); 1309 sb.append(message); 1310 Iterator <Map.Entry <IFile, IFile>> iter = pairs.entrySet().iterator(); 1311 while (true) { 1312 Map.Entry <IFile, IFile> entry = iter.next(); 1313 sb.append(entry.getKey().getName()); 1314 sb.append("->"); sb.append(entry.getValue().getName()); 1316 if (!iter.hasNext()) { 1317 break; 1318 } 1319 sb.append(", "); } 1321 String s = sb.toString(); 1322 AptPlugin.log(new IllegalStateException (s), s); 1323 } 1324 1325 1329 private void logExtraFiles(String message, Iterable <IFile> files) { 1330 StringBuilder sb = new StringBuilder (); 1331 sb.append(message); 1332 Iterator <IFile> iter = files.iterator(); 1333 while (true) { 1334 sb.append(iter.next().getName()); 1335 if (!iter.hasNext()) { 1336 break; 1337 } 1338 sb.append(", "); } 1340 String s = sb.toString(); 1341 AptPlugin.log(new IllegalStateException (s), s); 1342 } 1343 1344 1356 private static String [] parseTypeName(String qualifiedName) { 1357 1358 if (qualifiedName.indexOf('/') != -1) 1360 qualifiedName = qualifiedName.replace('/', '.'); 1361 1362 String [] names = new String [2]; 1363 String pkgName; 1364 String fname; 1365 int idx = qualifiedName.lastIndexOf( '.' ); 1366 if ( idx > 0 ) 1367 { 1368 pkgName = qualifiedName.substring( 0, idx ); 1369 fname = 1370 qualifiedName.substring(idx + 1, qualifiedName.length()) + ".java"; } 1372 else 1373 { 1374 pkgName = ""; fname = qualifiedName + ".java"; } 1377 names[0] = pkgName; 1378 names[1] = fname; 1379 return names; 1380 } 1381 1382 1397 private synchronized List <IFile> removeFileFromBuildMaps(IFile f) 1398 { 1399 List <IFile> toDelete = new ArrayList <IFile>(); 1400 Set <IFile> childFiles = _buildDeps.getValues(f); 1404 for (IFile childFile : childFiles) { 1405 Set <IFile> parentFiles = _buildDeps.getKeys(childFile); 1406 if (parentFiles.size() == 1 && parentFiles.contains(f)) { 1407 toDelete.add(childFile); 1408 } 1409 } 1410 boolean removed = _buildDeps.removeKey(f); 1411 if (removed) { 1412 if (AptPlugin.DEBUG_GFM_MAPS) AptPlugin.trace( 1413 "removed parent file from build dependencies: " + f); } 1415 1416 assert checkIntegrity(); 1417 return toDelete; 1418 } 1419 1420 1436 private synchronized List <ICompilationUnit> removeFileFromReconcileMaps(IFile file) 1437 { 1438 List <ICompilationUnit> toDiscard = new ArrayList <ICompilationUnit>(); 1439 Set <IFile> genFiles = _reconcileDeps.getValues(file); 1441 for (IFile child : genFiles) { 1442 if (hasNoOtherReconcileParents(child, file)) { 1443 ICompilationUnit childWC = _reconcileGenTypes.remove(child); 1444 assert null != childWC : "Every value in _reconcileDeps must be a key in _reconcileGenTypes"; toDiscard.add(childWC); 1446 } 1447 } 1448 _reconcileDeps.removeKey(file); 1449 1450 Set <IFile> nonGenFiles = _reconcileNonDeps.getValues(file); 1452 for (IFile child : nonGenFiles) { 1453 ICompilationUnit hidingWC = _hiddenBuiltTypes.remove(child); 1454 if (null != hidingWC) { 1455 toDiscard.add(hidingWC); 1456 } 1457 } 1458 _reconcileNonDeps.removeKey(file); 1459 1460 assert checkIntegrity(); 1461 return toDiscard; 1462 } 1463 1464 1490 private void saveCompilationUnit(IPackageFragment pkgFrag, final String cuName, String contents, 1491 IProgressMonitor progressMonitor) 1492 { 1493 1494 ICompilationUnit unit = pkgFrag.getCompilationUnit(cuName); 1495 boolean isWorkingCopy = unit.isWorkingCopy(); 1496 if (isWorkingCopy) { 1497 try { 1498 _CUHELPER.commitNewContents(unit, contents, progressMonitor); 1501 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 1502 "Committed existing working copy during build: " + unit.getElementName()); } 1504 catch (JavaModelException e) { 1505 if (e.getJavaModelStatus().getCode() == IJavaModelStatusConstants.INVALID_RESOURCE) { 1508 _CUHELPER.discardWorkingCopy(unit); 1509 isWorkingCopy = false; 1510 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 1511 "Discarded invalid existing working copy in order to try again: " + unit.getElementName()); } 1513 else { 1514 AptPlugin.log(e, "Unable to commit working copy to disk: " + unit.getElementName()); return; 1516 } 1517 } 1518 } 1519 if (!isWorkingCopy) { 1520 try { 1521 unit = pkgFrag.createCompilationUnit(cuName, contents, true, progressMonitor); 1522 if (AptPlugin.DEBUG_GFM) AptPlugin.trace( 1523 "Created compilation unit during build: " + unit.getElementName()); } catch (JavaModelException e) { 1525 AptPlugin.log(e, "Unable to create compilation unit on disk: " + cuName + " in pkg fragment: " + pkgFrag.getElementName()); } 1528 } 1529 } 1530 1531} 1532 | Popular Tags |