private static void flushPreference(String optionName, IEclipsePreferences node) {
   try {
     node.flush();
   } catch (BackingStoreException e) {
     AptPlugin.log(e, "Failed to save preference: " + optionName); // $NON-NLS-1$
   }
 }
  /**
   * Set all the processor options in one call. This will delete any options that are not passed in,
   * so callers who do not wish to destroy pre-existing options should use addProcessorOption()
   * instead.
   *
   * @param options a map of keys to values. The keys should not include any automatic options (@see
   *     #isAutomaticProcessorOption(String)), and the "-A" should not be included. That is, to
   *     perform the equivalent of the apt command line "-Afoo=bar", use the key "foo" and the value
   *     "bar". Keys cannot contain spaces; values can contain anything at all. Keys cannot be null,
   *     but values can be.
   */
  public static void setProcessorOptions(Map<String, String> options, IJavaProject jproj) {
    IScopeContext context =
        (null != jproj) ? new ProjectScope(jproj.getProject()) : InstanceScope.INSTANCE;

    // TODO: this call is needed only for backwards compatibility with
    // settings files previous to 2005.11.13.  At some point it should be
    // removed.
    removeOldStyleSettings(context);

    IEclipsePreferences node =
        context.getNode(
            AptPlugin.PLUGIN_ID
                + "/"
                + //$NON-NLS-1$
                AptPreferenceConstants.APT_PROCESSOROPTIONS);
    try {
      node.clear();
      for (Entry<String, String> option : options.entrySet()) {
        String nonNullVal =
            option.getValue() == null ? AptPreferenceConstants.APT_NULLVALUE : option.getValue();
        node.put(option.getKey(), nonNullVal);
      }
      node.flush();
    } catch (BackingStoreException e) {
      AptPlugin.log(e, "Unable to save annotation processor options"); // $NON-NLS-1$
    }
  }
 /**
  * Turn annotation processing on or off for this project.
  *
  * <p>Prior to Eclipse 3.3, this affected the org.eclipse.jdt.apt.aptEnabled setting. In Eclipse
  * 3.3, it affects the org.eclipse.jdt.core.compiler.processingEnabled setting; the older setting
  * is still set (and read) in order to preserve backward compatibility.
  *
  * @param jproject an IJavaProject, or null to set workspace preferences.
  * @param enabled
  */
 public static void setEnabled(IJavaProject jproject, boolean enabled) {
   if (jproject == null && enabled == true) {
     IllegalArgumentException e = new IllegalArgumentException();
     IStatus status =
         AptPlugin.createWarningStatus(
             e, "Illegal attempt to enable annotation processing workspace-wide"); // $NON-NLS-1$
     AptPlugin.log(status);
     throw e;
   }
   setString(
       jproject,
       AptPreferenceConstants.APT_PROCESSANNOTATIONS,
       enabled ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED);
   // backward compatibility: also save old setting
   setBoolean(jproject, AptPreferenceConstants.APT_ENABLED, enabled);
 }
 /**
  * Flush unsaved preferences and perform any other config-related shutdown. This is called once,
  * from AptPlugin.shutdown().
  */
 public static void dispose() {
   try {
     InstanceScope.INSTANCE.getNode(AptPlugin.PLUGIN_ID).flush();
   } catch (BackingStoreException e) {
     // log failure and continue
     AptPlugin.log(e, "Couldn't flush preferences to disk"); // $NON-NLS-1$
   }
 }
  // We need this as a separate method, as we'll put dependent projects' output
  // on the classpath
  private static void addProjectClasspath(
      IWorkspaceRoot root,
      IJavaProject otherJavaProject,
      Set<IJavaProject> projectsProcessed,
      Set<String> classpath) {

    // Check for cycles. If we've already seen this project,
    // no need to go any further.
    if (projectsProcessed.contains(otherJavaProject)) {
      return;
    }
    projectsProcessed.add(otherJavaProject);

    try {
      // Add the output directory first as a binary entry for other projects
      IPath binPath = otherJavaProject.getOutputLocation();
      IResource binPathResource = root.findMember(binPath);
      String binDirString;
      if (binPathResource != null) {
        binDirString = root.findMember(binPath).getLocation().toOSString();
      } else {
        binDirString = binPath.toOSString();
      }
      classpath.add(binDirString);

      // Now the rest of the classpath
      IClasspathEntry[] classpathEntries = otherJavaProject.getResolvedClasspath(true);
      for (IClasspathEntry entry : classpathEntries) {
        if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
          IPath cpPath = entry.getPath();

          IResource res = root.findMember(cpPath);

          // If res is null, the path is absolute (it's an external jar)
          if (res == null) {
            classpath.add(cpPath.toOSString());
          } else {
            // It's relative
            classpath.add(res.getLocation().toOSString());
          }
        } else if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
          IPath otherProjectPath = entry.getPath();
          IProject otherProject = root.getProject(otherProjectPath.segment(0));
          IJavaProject yetAnotherJavaProject = JavaCore.create(otherProject);
          if (yetAnotherJavaProject != null) {
            addProjectClasspath(root, yetAnotherJavaProject, projectsProcessed, classpath);
          }
        }
        // Ignore source types
      }
    } catch (JavaModelException jme) {
      AptPlugin.log(
          jme,
          "Failed to get the classpath for the following project: "
              + otherJavaProject); //$NON-NLS-1$
    }
  }
 private static void setBoolean(IJavaProject jproject, String optionName, boolean value) {
   IScopeContext context =
       (null != jproject) ? new ProjectScope(jproject.getProject()) : InstanceScope.INSTANCE;
   IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID);
   // get old val as a String, so it can be null if setting doesn't exist yet
   String oldValue = node.get(optionName, null);
   node.putBoolean(optionName, value);
   if (jproject != null && oldValue == null || (value != Boolean.parseBoolean(oldValue))) {
     AptProject aproj = AptPlugin.getAptProject(jproject);
     aproj.preferenceChanged(optionName);
   }
   flushPreference(optionName, node);
 }
 /**
  * Set the org.eclipse.jdt.core.compiler.processAnnotations setting. In Eclipse 3.3, this value
  * replaces org.eclipse.jdt.apt.aptEnabled, but we continue to set both values in order to ensure
  * backward compatibility with prior versions. the aptEnabled setting.
  *
  * @param enable
  */
 private void setJDTProcessAnnotationsSetting(boolean enable) {
   IScopeContext context =
       (null != fJProj) ? new ProjectScope(fJProj.getProject()) : InstanceScope.INSTANCE;
   IEclipsePreferences node = context.getNode(JavaCore.PLUGIN_ID);
   final String value = enable ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED;
   node.put(AptPreferenceConstants.APT_PROCESSANNOTATIONS, value);
   try {
     node.flush();
   } catch (BackingStoreException e) {
     AptPlugin.log(
         e,
         "Failed to save preference: "
             + AptPreferenceConstants.APT_PROCESSANNOTATIONS); // $NON-NLS-1$
   }
 }
 private static void setString(IJavaProject jproject, String optionName, String value) {
   IScopeContext context =
       (null != jproject) ? new ProjectScope(jproject.getProject()) : InstanceScope.INSTANCE;
   IEclipsePreferences node;
   if (AptPreferenceConstants.APT_PROCESSANNOTATIONS.equals(optionName)) {
     node = context.getNode(JavaCore.PLUGIN_ID);
   } else {
     node = context.getNode(AptPlugin.PLUGIN_ID);
   }
   String oldValue = node.get(optionName, null);
   node.put(optionName, value);
   if (jproject != null && !value.equals(oldValue)) {
     AptProject aproj = AptPlugin.getAptProject(jproject);
     aproj.preferenceChanged(optionName);
   }
   flushPreference(optionName, node);
 }
  /**
   * Get the options that are presented to annotation processors by the
   * AnnotationProcessorEnvironment. The -A and = are stripped out, so (key, value) is the
   * equivalent of -Akey=value.
   *
   * <p>This method differs from getProcessorOptions in that the options returned by this method do
   * NOT include any programmatically set options. This method returns only the options that are
   * persisted to the preference store and that are displayed in the configuration GUI.
   *
   * @param jproj a project, or null to query the workspace-wide setting. If jproj is not null, but
   *     the project has no per-project settings, this method will fall back to the workspace-wide
   *     settings.
   * @return a mutable, possibly empty, map of (key, value) pairs. The value part of a pair may be
   *     null (equivalent to "-Akey"). The value part can contain spaces, if it is quoted:
   *     -Afoo="bar baz".
   */
  public static Map<String, String> getRawProcessorOptions(IJavaProject jproj) {
    Map<String, String> options = new HashMap<String, String>();

    // TODO: this code is needed only for backwards compatibility with
    // settings files previous to 2005.11.13.  At some point it should be
    // removed.
    // If an old-style setting exists, add it into the mix for backward
    // compatibility.
    options.putAll(getOldStyleRawProcessorOptions(jproj));

    // Fall back from project to workspace scope on an all-or-nothing basis,
    // not value by value.  (Never fall back to default scope; there are no
    // default processor options.)  We can't use IPreferencesService for this
    // as we would normally do, because we don't know the names of the keys.
    IScopeContext[] contexts;
    if (jproj != null) {
      contexts = new IScopeContext[] {new ProjectScope(jproj.getProject()), InstanceScope.INSTANCE};
    } else {
      contexts = new IScopeContext[] {InstanceScope.INSTANCE};
    }
    for (IScopeContext context : contexts) {
      IEclipsePreferences prefs = context.getNode(AptPlugin.PLUGIN_ID);
      try {
        if (prefs.childrenNames().length > 0) {
          IEclipsePreferences procOptionsNode =
              context.getNode(
                  AptPlugin.PLUGIN_ID
                      + "/"
                      + AptPreferenceConstants.APT_PROCESSOROPTIONS); // $NON-NLS-1$
          if (procOptionsNode != null) {
            for (String key : procOptionsNode.keys()) {
              String nonNullVal = procOptionsNode.get(key, null);
              String val =
                  AptPreferenceConstants.APT_NULLVALUE.equals(nonNullVal) ? null : nonNullVal;
              options.put(key, val);
            }
            break;
          }
        }
      } catch (BackingStoreException e) {
        AptPlugin.log(e, "Unable to load annotation processor options"); // $NON-NLS-1$
      }
    }
    return options;
  }
 /**
  * Remove an option from the list of processor options.
  *
  * @param jproj a project, or null to remove the option workspace-wide.
  * @param key must be a nonempty string. It should only include the key; that is, it should not
  *     start with "-A".
  */
 public static void removeProcessorOption(IJavaProject jproj, String key) {
   if (key == null || key.length() < 1) {
     throw new IllegalArgumentException();
   }
   IScopeContext context =
       (null != jproj) ? new ProjectScope(jproj.getProject()) : InstanceScope.INSTANCE;
   IEclipsePreferences node =
       context.getNode(
           AptPlugin.PLUGIN_ID
               + "/"
               + //$NON-NLS-1$
               AptPreferenceConstants.APT_PROCESSOROPTIONS);
   node.remove(key);
   try {
     node.flush();
   } catch (BackingStoreException e) {
     AptPlugin.log(e, "Unable to save annotation processor option" + key); // $NON-NLS-1$
   }
 }
  /**
   * Get the options that are presented to annotation processors by the
   * AnnotationProcessorEnvironment. Options are key/value pairs which are set in the project
   * properties.
   *
   * <p>Option values can begin with a percent-delimited token representing a classpath variable or
   * one of several predefined values. The token must either be followed by a path delimiter, or be
   * the entire value. Such tokens will be replaced with their resolved value. The predefined values
   * are <code>%ROOT%</code>, which is replaced by the absolute pathname of the workspace root
   * directory, and <code>%PROJECT.DIR%</code>, which will be replaced by the absolute pathname of
   * the project root directory. For example, a value of <code>
   * %ECLIPSE_HOME%/configuration/config.ini</code> might be resolved to <code>
   * d:/eclipse/configuration/config.ini</code>.
   *
   * <p>This method returns some options which are set programmatically but are not directly
   * editable, are not displayed in the configuration GUI, and are not persisted to the preference
   * store. This is meant to emulate the behavior of Sun's apt command-line tool, which passes most
   * of its command line options to the processor environment. The programmatically set options are:
   * <code>-classpath</code> [set to Java build path] <code>-sourcepath</code> [set to Java source
   * path] <code>-s</code> [set to generated src dir] <code>-d</code> [set to binary output dir]
   * <code>-target</code> [set to compiler target version] <code>-source</code> [set to compiler
   * source version]
   *
   * <p>There are some slight differences between the options returned by this method and the
   * options returned from this implementation of @see AnnotationProcessorEnvironment#getOptions().
   * First, that method returns additional options which are only meaningful during a build, such as
   * <code>phase</code>. Second, that method also adds alternate encodings of each option, to be
   * compatible with a bug in Sun's apt implementation: specifically, for each option key="k",
   * value="v", an additional option is created with key="-Ak=v", value=null. This includes the
   * user-created options, but does not include the programmatically defined options listed above.
   *
   * @param jproj a project, or null to query the workspace-wide setting.
   * @return a mutable, possibly empty, map of (key, value) pairs. The value part of a pair may be
   *     null (equivalent to "-Akey" on the Sun apt command line). The value part may contain
   *     spaces.
   */
  public static Map<String, String> getProcessorOptions(IJavaProject jproj) {
    Map<String, String> rawOptions = getRawProcessorOptions(jproj);
    // map is large enough to also include the programmatically generated options
    Map<String, String> options = new HashMap<String, String>(rawOptions.size() + 6);

    // Resolve path metavariables like %ROOT%
    for (Map.Entry<String, String> entry : rawOptions.entrySet()) {
      String resolvedValue = resolveVarPath(jproj, entry.getValue());
      String value = (resolvedValue == null) ? entry.getValue() : resolvedValue;
      options.put(entry.getKey(), value);
    }

    if (jproj == null) {
      // there are no programmatically set options at the workspace level
      return options;
    }

    IWorkspaceRoot root = jproj.getProject().getWorkspace().getRoot();

    // Add sourcepath and classpath variables
    try {
      IClasspathEntry[] classpathEntries = jproj.getResolvedClasspath(true);
      Set<String> classpath = new LinkedHashSet<String>();
      Set<String> sourcepath = new LinkedHashSet<String>();

      // For projects on the classpath, loops can exist; need to make sure we
      // don't loop forever
      Set<IJavaProject> projectsProcessed = new HashSet<IJavaProject>();
      projectsProcessed.add(jproj);
      for (IClasspathEntry entry : classpathEntries) {
        int kind = entry.getEntryKind();
        if (kind == IClasspathEntry.CPE_LIBRARY) {
          IPath cpPath = entry.getPath();

          IResource res = root.findMember(cpPath);

          // If res is null, the path is absolute (it's an external jar)
          if (res == null) {
            classpath.add(cpPath.toOSString());
          } else {
            // It's relative
            classpath.add(res.getLocation().toOSString());
          }
        } else if (kind == IClasspathEntry.CPE_SOURCE) {
          IResource res = root.findMember(entry.getPath());
          if (res == null) {
            continue;
          }
          IPath srcPath = res.getLocation();
          if (srcPath == null) {
            continue;
          }

          sourcepath.add(srcPath.toOSString());
        } else if (kind == IClasspathEntry.CPE_PROJECT) {
          // Add the dependent project's build path and classpath to ours
          IPath otherProjectPath = entry.getPath();
          IProject otherProject = root.getProject(otherProjectPath.segment(0));

          // Note: JavaCore.create() is safe, even if the project is null --
          // in that case, we get null back
          IJavaProject otherJavaProject = JavaCore.create(otherProject);

          // If it doesn't exist, ignore it
          if (otherJavaProject != null && otherJavaProject.isOpen()) {
            addProjectClasspath(root, otherJavaProject, projectsProcessed, classpath);
          }
        }
      }
      // if you add options here, also add them in isAutomaticProcessorOption(),
      // and document them in docs/reference/automatic_processor_options.html.

      // Classpath and sourcepath
      options.put("-classpath", convertPathCollectionToString(classpath)); // $NON-NLS-1$    	
      options.put("-sourcepath", convertPathCollectionToString(sourcepath)); // $NON-NLS-1$

      // Get absolute path for generated source dir
      IFolder genSrcDir = jproj.getProject().getFolder(getGenSrcDir(jproj));
      String genSrcDirString = genSrcDir.getRawLocation().toOSString();
      options.put("-s", genSrcDirString); // $NON-NLS-1$

      // Absolute path for bin dir as well
      IPath binPath = jproj.getOutputLocation();
      IResource binPathResource = root.findMember(binPath);
      String binDirString;
      if (binPathResource != null) {
        binDirString = root.findMember(binPath).getLocation().toOSString();
      } else {
        binDirString = binPath.toOSString();
      }
      options.put("-d", binDirString); // $NON-NLS-1$

      String target = jproj.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true);
      options.put("-target", target); // $NON-NLS-1$

      String source = jproj.getOption(JavaCore.COMPILER_SOURCE, true);
      options.put("-source", source); // $NON-NLS-1$
    } catch (JavaModelException jme) {
      AptPlugin.log(jme, "Could not get the classpath for project: " + jproj); // $NON-NLS-1$
    }

    return options;
  }