1 12 package org.eclipse.jdt.apt.core.util; 13 14 import java.io.File ; 15 import java.util.Collection ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.LinkedHashSet ; 19 import java.util.Map ; 20 import java.util.Set ; 21 import java.util.Map.Entry; 22 import java.util.regex.Pattern ; 23 24 import org.eclipse.core.resources.IFolder; 25 import org.eclipse.core.resources.IProject; 26 import org.eclipse.core.resources.IResource; 27 import org.eclipse.core.resources.IWorkspaceRoot; 28 import org.eclipse.core.resources.ProjectScope; 29 import org.eclipse.core.resources.ResourcesPlugin; 30 import org.eclipse.core.runtime.CoreException; 31 import org.eclipse.core.runtime.IPath; 32 import org.eclipse.core.runtime.IStatus; 33 import org.eclipse.core.runtime.Path; 34 import org.eclipse.core.runtime.Platform; 35 import org.eclipse.core.runtime.preferences.DefaultScope; 36 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 37 import org.eclipse.core.runtime.preferences.IPreferencesService; 38 import org.eclipse.core.runtime.preferences.IScopeContext; 39 import org.eclipse.core.runtime.preferences.InstanceScope; 40 import org.eclipse.jdt.apt.core.internal.AnnotationProcessorFactoryLoader; 41 import org.eclipse.jdt.apt.core.internal.AptPlugin; 42 import org.eclipse.jdt.apt.core.internal.AptProject; 43 import org.eclipse.jdt.apt.core.internal.generatedfile.GeneratedSourceFolderManager; 44 import org.eclipse.jdt.apt.core.internal.util.FactoryPath; 45 import org.eclipse.jdt.apt.core.internal.util.FactoryPathUtil; 46 import org.eclipse.jdt.core.IClasspathEntry; 47 import org.eclipse.jdt.core.IJavaProject; 48 import org.eclipse.jdt.core.JavaCore; 49 import org.eclipse.jdt.core.JavaModelException; 50 import org.osgi.service.prefs.BackingStoreException; 51 52 62 public class AptConfig { 63 64 65 private static final String PATHVAR_TOKEN = "^%[^%/\\\\ ]+%.*"; 67 private static final String PATHVAR_ROOT = "%ROOT%"; 69 private static final String PATHVAR_PROJECTROOT = "%PROJECT.DIR%"; 71 74 private AptConfig() {} 75 76 84 public static void addProcessorOption(IJavaProject jproj, String key, String val) { 85 if (key == null || key.length() < 1) { 86 throw new IllegalArgumentException (); 87 } 88 IScopeContext context = (null != jproj) ? 89 new ProjectScope(jproj.getProject()) : new InstanceScope(); 90 IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID + "/" + AptPreferenceConstants.APT_PROCESSOROPTIONS); 92 String nonNullVal = val == null ? AptPreferenceConstants.APT_NULLVALUE : val; 93 node.put(key, nonNullVal); 94 try { 95 node.flush(); 96 } catch (BackingStoreException e) { 97 AptPlugin.log(e, "Unable to save annotation processor option" + key); } 99 } 100 101 107 public static void removeProcessorOption(IJavaProject jproj, String key) { 108 if (key == null || key.length() < 1) { 109 throw new IllegalArgumentException (); 110 } 111 IScopeContext context = (null != jproj) ? 112 new ProjectScope(jproj.getProject()) : new InstanceScope(); 113 IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID + "/" + AptPreferenceConstants.APT_PROCESSOROPTIONS); 115 node.remove(key); 116 try { 117 node.flush(); 118 } catch (BackingStoreException e) { 119 AptPlugin.log(e, "Unable to save annotation processor option" + key); } 121 } 122 123 168 public static Map <String , String > getProcessorOptions(IJavaProject jproj) { 169 Map <String ,String > rawOptions = getRawProcessorOptions(jproj); 170 Map <String , String > options = new HashMap <String , String >(rawOptions.size() + 6); 172 173 for (Map.Entry <String , String > entry : rawOptions.entrySet()) { 175 String resolvedValue = resolveVarPath(jproj, entry.getValue()); 176 String value = (resolvedValue == null) ? entry.getValue() : resolvedValue; 177 options.put(entry.getKey(), value); 178 } 179 180 if (jproj == null) { 181 return options; 183 } 184 185 IWorkspaceRoot root = jproj.getProject().getWorkspace().getRoot(); 186 187 try { 189 IClasspathEntry[] classpathEntries = jproj.getResolvedClasspath(true); 190 Set <String > classpath = new LinkedHashSet <String >(); 191 Set <String > sourcepath = new LinkedHashSet <String >(); 192 193 Set <IJavaProject> projectsProcessed = new HashSet <IJavaProject>(); 196 projectsProcessed.add(jproj); 197 for (IClasspathEntry entry : classpathEntries) { 198 int kind = entry.getEntryKind(); 199 if (kind == IClasspathEntry.CPE_LIBRARY) { 200 IPath cpPath = entry.getPath(); 201 202 IResource res = root.findMember(cpPath); 203 204 if (res == null) { 206 classpath.add(cpPath.toOSString()); 207 } 208 else { 209 classpath.add(res.getLocation().toOSString()); 211 } 212 } 213 else if (kind == IClasspathEntry.CPE_SOURCE) { 214 IResource res = root.findMember(entry.getPath()); 215 if (res == null) { 216 continue; 217 } 218 IPath srcPath = res.getLocation(); 219 if (srcPath == null) { 220 continue; 221 } 222 223 sourcepath.add(srcPath.toOSString()); 224 } 225 else if (kind == IClasspathEntry.CPE_PROJECT) { 226 IPath otherProjectPath = entry.getPath(); 228 IProject otherProject = root.getProject(otherProjectPath.segment(0)); 229 230 IJavaProject otherJavaProject = JavaCore.create(otherProject); 233 234 if (otherJavaProject != null && otherJavaProject.isOpen()) { 236 addProjectClasspath(root, otherJavaProject, projectsProcessed, classpath); 237 } 238 } 239 } 240 243 options.put("-classpath",convertPathCollectionToString(classpath)); options.put("-sourcepath", convertPathCollectionToString(sourcepath)); 247 IFolder genSrcDir = jproj.getProject().getFolder(getGenSrcDir(jproj)); 249 String genSrcDirString = genSrcDir.getRawLocation().toOSString(); 250 options.put("-s", genSrcDirString); 252 IPath binPath = jproj.getOutputLocation(); 254 IResource binPathResource = root.findMember(binPath); 255 String binDirString; 256 if (binPathResource != null) { 257 binDirString = root.findMember(binPath).getLocation().toOSString(); 258 } 259 else { 260 binDirString = binPath.toOSString(); 261 } 262 options.put("-d", binDirString); 264 String target = jproj.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true); 265 options.put("-target", target); 267 String source = jproj.getOption(JavaCore.COMPILER_SOURCE, true); 268 options.put("-source", source); } 270 catch (JavaModelException jme) { 271 AptPlugin.log(jme, "Could not get the classpath for project: " + jproj); } 273 274 return options; 275 } 276 277 282 private static String resolveVarPath(IJavaProject jproj, String value) { 283 if (value == null) { 284 return null; 285 } 286 if (!Pattern.matches(PATHVAR_TOKEN, value)) { 288 return value; 289 } 290 IPath path = new Path(value); 291 String firstToken = path.segment(0); 292 if (PATHVAR_ROOT.equals(firstToken)) { 294 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); 295 IResource proj = root.findMember(path.segment(1)); 296 if (proj == null) { 297 return value; 298 } 299 IPath relativePath = path.removeFirstSegments(2); 301 IPath absoluteProjPath = proj.getLocation(); 302 IPath absoluteResPath = absoluteProjPath.append(relativePath); 303 return absoluteResPath.toOSString(); 304 } 305 306 if (jproj != null && PATHVAR_PROJECTROOT.equals(firstToken)) { 308 IPath relativePath = path.removeFirstSegments(1); 310 IPath absoluteProjPath = jproj.getProject().getLocation(); 311 IPath absoluteResPath = absoluteProjPath.append(relativePath); 312 return absoluteResPath.toOSString(); 313 } 314 315 String cpvName = firstToken.substring(1, firstToken.length() - 1); 317 IPath cpvPath = JavaCore.getClasspathVariable(cpvName); 318 if (cpvPath != null) { 319 IPath resolved = cpvPath.append(path.removeFirstSegments(1)); 320 return resolved.toOSString(); 321 } 322 else { 323 return value; 324 } 325 } 326 327 private static void addProjectClasspath( 330 IWorkspaceRoot root, 331 IJavaProject otherJavaProject, 332 Set <IJavaProject> projectsProcessed, 333 Set <String > classpath) { 334 335 if (projectsProcessed.contains(otherJavaProject)) { 338 return; 339 } 340 projectsProcessed.add(otherJavaProject); 341 342 try { 343 IPath binPath = otherJavaProject.getOutputLocation(); 345 IResource binPathResource = root.findMember(binPath); 346 String binDirString; 347 if (binPathResource != null) { 348 binDirString = root.findMember(binPath).getLocation().toOSString(); 349 } 350 else { 351 binDirString = binPath.toOSString(); 352 } 353 classpath.add(binDirString); 354 355 IClasspathEntry[] classpathEntries = otherJavaProject.getResolvedClasspath(true); 357 for (IClasspathEntry entry : classpathEntries) { 358 if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { 359 IPath cpPath = entry.getPath(); 360 361 IResource res = root.findMember(cpPath); 362 363 if (res == null) { 365 classpath.add(cpPath.toOSString()); 366 } 367 else { 368 classpath.add(res.getLocation().toOSString()); 370 } 371 } 372 else if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { 373 IPath otherProjectPath = entry.getPath(); 374 IProject otherProject = root.getProject(otherProjectPath.segment(0)); 375 IJavaProject yetAnotherJavaProject = JavaCore.create(otherProject); 376 if (yetAnotherJavaProject != null) { 377 addProjectClasspath(root, yetAnotherJavaProject, projectsProcessed, classpath); 378 } 379 } 380 } 382 } 383 catch (JavaModelException jme) { 384 AptPlugin.log(jme, "Failed to get the classpath for the following project: " + otherJavaProject); } 386 } 387 388 private static String convertPathCollectionToString(Collection <String > paths) { 389 if (paths.size() == 0) { 390 return ""; } 392 StringBuilder sb = new StringBuilder (); 393 boolean first = true; 394 for (String path : paths) { 395 if (first) { 396 first = false; 397 } 398 else { 399 sb.append(File.pathSeparatorChar); 400 } 401 sb.append(path); 402 } 403 return sb.toString(); 404 } 405 406 417 public static void setProcessorOptions(Map <String , String > options, IJavaProject jproj) { 418 IScopeContext context = (null != jproj) ? 419 new ProjectScope(jproj.getProject()) : new InstanceScope(); 420 421 removeOldStyleSettings(context); 425 426 IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID + "/" + AptPreferenceConstants.APT_PROCESSOROPTIONS); 428 try { 429 node.clear(); 430 for (Entry<String , String > option : options.entrySet()) { 431 String nonNullVal = option.getValue() == null ? 432 AptPreferenceConstants.APT_NULLVALUE : option.getValue(); 433 node.put(option.getKey(), nonNullVal); 434 } 435 node.flush(); 436 } catch (BackingStoreException e) { 437 AptPlugin.log(e, "Unable to save annotation processor options"); } 439 } 440 441 447 public static boolean isAutomaticProcessorOption(String key) { 448 if ("-classpath".equals(key)) return true; 450 if ("-sourcepath".equals(key)) return true; 452 if ("-s".equals(key)) return true; 454 if ("-d".equals(key)) return true; 456 if ("-target".equals(key)) return true; 458 if ("-source".equals(key)) return true; 460 return false; 461 } 462 463 480 public static Map <String , String > getRawProcessorOptions(IJavaProject jproj) { 481 Map <String , String > options = new HashMap <String , String >(); 482 483 options.putAll(getOldStyleRawProcessorOptions(jproj)); 489 490 IScopeContext[] contexts; 495 if (jproj != null) { 496 contexts = new IScopeContext[] { 497 new ProjectScope(jproj.getProject()), new InstanceScope() }; 498 } 499 else { 500 contexts = new IScopeContext[] { new InstanceScope() }; 501 } 502 for (IScopeContext context : contexts) { 503 IEclipsePreferences prefs = context.getNode(AptPlugin.PLUGIN_ID); 504 try { 505 if (prefs.childrenNames().length > 0) { 506 IEclipsePreferences procOptionsNode = context.getNode( 507 AptPlugin.PLUGIN_ID + "/" + AptPreferenceConstants.APT_PROCESSOROPTIONS); if (procOptionsNode != null) { 509 for (String key : procOptionsNode.keys()) { 510 String nonNullVal = procOptionsNode.get(key, null); 511 String val = AptPreferenceConstants.APT_NULLVALUE.equals(nonNullVal) ? 512 null : nonNullVal; 513 options.put(key, val); 514 } 515 break; 516 } 517 } 518 } catch (BackingStoreException e) { 519 AptPlugin.log(e, "Unable to load annotation processor options"); } 521 } 522 return options; 523 } 524 525 531 private static Map <String , String > getOldStyleRawProcessorOptions(IJavaProject jproj) { 532 Map <String , String > options; 533 String allOptions = getString(jproj, AptPreferenceConstants.APT_PROCESSOROPTIONS); 534 if (null == allOptions) { 535 options = new HashMap <String , String >(); 536 } 537 else { 538 ProcessorOptionsParser op = new ProcessorOptionsParser(allOptions); 539 options = op.parse(); 540 } 541 return options; 542 } 543 553 private static class ProcessorOptionsParser { 554 final String _s; 555 int _start; boolean _hasVal; 558 public ProcessorOptionsParser(String s) { 559 _s = s; 560 _start = 0; 561 _hasVal = false; 562 } 563 564 public Map <String , String > parse() { 565 Map <String , String > options = new HashMap <String , String >(); 566 String key; 567 while (null != (key = parseKey())) { 568 options.put(key, parseVal()); 569 } 570 return options; 571 } 572 573 581 private String parseKey() { 582 String key; 583 int spaceAt = -1; 584 int equalsAt = -1; 585 586 _hasVal = false; 587 588 while (true) { 589 _start = _s.indexOf("-A", _start); if (_start < 0) { 591 return null; 592 } 593 594 _start += 2; 596 if (_start >= _s.length()) { 597 return null; 599 } 600 601 spaceAt = _s.indexOf(' ', _start); 602 equalsAt = _s.indexOf('=', _start); 603 if (spaceAt == _start || equalsAt == _start) { 604 ++_start; 606 continue; 607 } 608 break; 609 } 610 611 if (equalsAt > 0) { 614 if (spaceAt < 0 || equalsAt < spaceAt) { 615 key = new String (_s.substring(_start, equalsAt)); 617 _start = equalsAt + 1; 618 _hasVal = (_start < _s.length()); 619 } 620 else { 621 key = new String (_s.substring(_start, spaceAt)); 623 _start = spaceAt + 1; 624 } 625 } 626 else { 627 if (spaceAt < 0) { 628 key = new String (_s.substring(_start)); 630 _start = _s.length(); 631 } 632 else { 633 key = new String (_s.substring(_start, spaceAt)); 635 _start = spaceAt + 1; 636 } 637 } 638 return key; 639 } 640 641 648 private String parseVal() { 649 if (!_hasVal || _start < 0 || _start >= _s.length()) { 650 return null; 651 } 652 boolean inQuotedRegion = false; 653 int start = _start; 654 int end = _start; 655 while (end < _s.length()) { 656 char c = _s.charAt(end); 657 if (c == '"') { 658 inQuotedRegion = !inQuotedRegion; 659 } 660 else if (!inQuotedRegion && c == ' ') { 661 _start = end + 1; 663 break; 664 } 665 ++end; 666 } 667 668 return new String (_s.substring(start, end)); 669 } 670 } 671 672 679 private static void removeOldStyleSettings(IScopeContext context) { 680 IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID); 681 node.remove(AptPreferenceConstants.APT_PROCESSOROPTIONS); 682 } 683 684 688 public static void dispose() { 689 try { 690 new InstanceScope().getNode(AptPlugin.PLUGIN_ID).flush(); 691 } 692 catch (BackingStoreException e) { 693 AptPlugin.log(e, "Couldn't flush preferences to disk"); } 696 } 697 698 702 public static void initialize() { 703 } 706 707 717 public static boolean isEnabled(IJavaProject jproject) { 718 if ("enabled".equals(getString(jproject, AptPreferenceConstants.APT_PROCESSANNOTATIONS))) { return true; 720 } 721 return getBoolean(jproject, AptPreferenceConstants.APT_ENABLED); 723 } 724 725 726 736 public static void setEnabled(IJavaProject jproject, boolean enabled) { 737 if (jproject == null && enabled == true) { 738 IllegalArgumentException e = new IllegalArgumentException (); 739 IStatus status = AptPlugin.createWarningStatus(e, 740 "Illegal attempt to enable annotation processing workspace-wide"); AptPlugin.log(status); 742 throw e; 743 } 744 setString(jproject, AptPreferenceConstants.APT_PROCESSANNOTATIONS, 745 enabled ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED); 746 setBoolean(jproject, AptPreferenceConstants.APT_ENABLED, enabled); 748 } 749 750 757 public static boolean shouldProcessDuringReconcile(IJavaProject jproject) { 758 return getBoolean(jproject, AptPreferenceConstants.APT_RECONCILEENABLED); 759 } 760 761 768 public static void setProcessDuringReconcile(IJavaProject jproject, boolean enabled) { 769 setBoolean(jproject, AptPreferenceConstants.APT_RECONCILEENABLED, enabled); 770 } 771 772 private static boolean getBoolean(IJavaProject jproj, String optionName) { 773 IPreferencesService service = Platform.getPreferencesService(); 774 IScopeContext[] contexts; 775 if (jproj != null) { 776 contexts = new IScopeContext[] { 777 new ProjectScope(jproj.getProject()), new InstanceScope(), new DefaultScope() }; 778 } 779 else { 780 contexts = new IScopeContext[] { new InstanceScope(), new DefaultScope() }; 781 } 782 return service.getBoolean( 783 AptPlugin.PLUGIN_ID, 784 optionName, 785 Boolean.parseBoolean(AptPreferenceConstants.DEFAULT_OPTIONS_MAP.get(optionName)), 786 contexts); 787 } 788 789 795 public static IFactoryPath getDefaultFactoryPath(IJavaProject jproj) { 796 return FactoryPathUtil.getDefaultFactoryPath(jproj); 797 } 798 799 807 public static IFactoryPath getFactoryPath(IJavaProject jproj) { 808 return FactoryPathUtil.getFactoryPath(jproj); 809 } 810 811 817 public static void setFactoryPath(IJavaProject jproj, IFactoryPath path) 818 throws CoreException 819 { 820 FactoryPath fp = (FactoryPath)path; 821 FactoryPathUtil.setFactoryPath(jproj, fp); 822 if (jproj == null) { 825 AnnotationProcessorFactoryLoader.getLoader().resetAll(); 826 } 827 } 828 829 834 public static boolean hasProjectSpecificFactoryPath(IJavaProject jproj) { 835 if (null == jproj) { 836 return false; 838 } 839 return FactoryPathUtil.doesFactoryPathFileExist(jproj); 840 } 841 842 855 public static String getString(IJavaProject jproj, String optionName) { 856 IPreferencesService service = Platform.getPreferencesService(); 857 IScopeContext[] contexts; 858 if (jproj != null) { 859 contexts = new IScopeContext[] { 860 new ProjectScope(jproj.getProject()), new InstanceScope(), new DefaultScope() }; 861 } 862 else { 863 contexts = new IScopeContext[] { new InstanceScope(), new DefaultScope() }; 864 } 865 String pluginId = null; 866 if (AptPreferenceConstants.APT_PROCESSANNOTATIONS.equals(optionName)) { 867 pluginId = JavaCore.PLUGIN_ID; 868 } 869 else { 870 pluginId = AptPlugin.PLUGIN_ID; 871 } 872 return service.getString( 873 pluginId, 874 optionName, 875 AptPreferenceConstants.DEFAULT_OPTIONS_MAP.get(optionName), 876 contexts); 877 } 878 879 public static String getGenSrcDir(IJavaProject jproject) { 880 return getString(jproject, AptPreferenceConstants.APT_GENSRCDIR); 881 } 882 883 public static void setGenSrcDir(IJavaProject jproject, String dirString) { 884 if (!GeneratedSourceFolderManager.validate(jproject, dirString)) { 885 throw new IllegalArgumentException ("Illegal name for generated source folder: " + dirString); } 887 setString(jproject, AptPreferenceConstants.APT_GENSRCDIR, dirString); 888 } 889 890 public static boolean validateGenSrcDir(IJavaProject jproject, String dirName) { 891 return GeneratedSourceFolderManager.validate(jproject, dirName); 892 } 893 894 private static void setBoolean(IJavaProject jproject, String optionName, boolean value) { 895 IScopeContext context = (null != jproject) ? 896 new ProjectScope(jproject.getProject()) : new InstanceScope(); 897 IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID); 898 String oldValue = node.get(optionName, null); 900 node.putBoolean(optionName, value); 901 if (jproject != null && oldValue == null || (value != Boolean.parseBoolean(oldValue))) { 902 AptProject aproj = AptPlugin.getAptProject(jproject); 903 aproj.preferenceChanged(optionName); 904 } 905 flushPreference(optionName, node); 906 } 907 908 private static void setString(IJavaProject jproject, String optionName, String value) { 909 IScopeContext context = (null != jproject) ? 910 new ProjectScope(jproject.getProject()) : new InstanceScope(); 911 IEclipsePreferences node; 912 if (AptPreferenceConstants.APT_PROCESSANNOTATIONS.equals(optionName)) { 913 node = context.getNode(JavaCore.PLUGIN_ID); 914 } 915 else { 916 node = context.getNode(AptPlugin.PLUGIN_ID); 917 } 918 String oldValue = node.get(optionName, null); 919 node.put(optionName, value); 920 if (jproject != null && !value.equals(oldValue)) { 921 AptProject aproj = AptPlugin.getAptProject(jproject); 922 aproj.preferenceChanged(optionName); 923 } 924 flushPreference(optionName, node); 925 } 926 927 private static void flushPreference(String optionName, IEclipsePreferences node) { 928 try { 929 node.flush(); 930 } 931 catch (BackingStoreException e){ 932 AptPlugin.log(e, "Failed to save preference: " + optionName); } 934 } 935 936 } 937 | Popular Tags |