Add bootclasspath and extdir configuration to java_toolchain

Once this is released we can phase out --javac_bootclasspath and
--javac_extdir.

--
MOS_MIGRATED_REVID=115478455
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
index 9c7e410..a65204f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
@@ -92,6 +92,11 @@
    * Returns the javac bootclasspath artifacts.
    */
   protected final ImmutableList<Artifact> getBootClasspath() {
+    NestedSet<Artifact> toolchainBootclasspath =
+        JavaToolchainProvider.getDefaultBootclasspath(ruleContext);
+    if (toolchainBootclasspath != null) {
+      return ImmutableList.copyOf(toolchainBootclasspath);
+    }
     return ruleContext.getPrerequisiteArtifacts(
         "$javac_bootclasspath" + implicitAttributesSuffix, Mode.HOST).list();
   }
@@ -100,6 +105,11 @@
    * Returns the extdir artifacts.
    */
   protected final ImmutableList<Artifact> getExtdirInputs() {
+    NestedSet<Artifact> toolchainExtclasspath =
+        JavaToolchainProvider.getDefaultExtclasspath(ruleContext);
+    if (toolchainExtclasspath != null) {
+      return ImmutableList.copyOf(toolchainExtclasspath);
+    }
     return ruleContext.getPrerequisiteArtifacts(
         "$javac_extdir" + implicitAttributesSuffix, Mode.HOST).list();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
index 27ef175..fbda98c6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
@@ -23,6 +23,7 @@
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
@@ -39,17 +40,31 @@
   public ConfiguredTarget create(RuleContext ruleContext) {
     final String source = ruleContext.attributes().get("source_version", Type.STRING);
     final String target = ruleContext.attributes().get("target_version", Type.STRING);
+    final NestedSet<Artifact> bootclasspath = getBootclasspath(ruleContext);
+    final NestedSet<Artifact> extclasspath = getExtclasspath(ruleContext);
     final String encoding = ruleContext.attributes().get("encoding", Type.STRING);
     final List<String> xlint = ruleContext.attributes().get("xlint", Type.STRING_LIST);
     final List<String> misc = ruleContext.attributes().get("misc", Type.STRING_LIST);
     final List<String> jvmOpts = ruleContext.attributes().get("jvm_opts", Type.STRING_LIST);
+    // TODO(cushon): clean up nulls once migration from --javac_bootclasspath and --javac_extdir
+    // is complete, and java_toolchain.{bootclasspath,extclasspath} are mandatory
     final JavaToolchainData toolchainData =
-        new JavaToolchainData(source, target, encoding, xlint, misc, jvmOpts);
+        new JavaToolchainData(
+            source,
+            target,
+            bootclasspath != null ? Artifact.toExecPaths(bootclasspath) : null,
+            extclasspath != null ? Artifact.toExecPaths(extclasspath) : null,
+            encoding,
+            xlint,
+            misc,
+            jvmOpts);
     final JavaConfiguration configuration = ruleContext.getFragment(JavaConfiguration.class);
     Artifact headerCompiler = getTurbine(ruleContext);
     JavaToolchainProvider provider =
         new JavaToolchainProvider(
             toolchainData,
+            bootclasspath,
+            extclasspath,
             configuration.getDefaultJavacFlags(),
             configuration.getDefaultJavaBuilderJvmFlags(),
             headerCompiler);
@@ -75,4 +90,22 @@
     }
     return Iterables.getOnlyElement(artifacts);
   }
+
+  private NestedSet<Artifact> getBootclasspath(RuleContext ruleContext) {
+    TransitiveInfoCollection prerequisite =
+        ruleContext.getPrerequisite("bootclasspath", Mode.HOST);
+    if (prerequisite == null) {
+      return null;
+    }
+    return prerequisite.getProvider(FileProvider.class).getFilesToBuild();
+  }
+
+  private NestedSet<Artifact> getExtclasspath(RuleContext ruleContext) {
+    TransitiveInfoCollection prerequisite =
+        ruleContext.getPrerequisite("extclasspath", Mode.HOST);
+    if (prerequisite == null) {
+      return null;
+    }
+    return prerequisite.getProvider(FileProvider.class).getFilesToBuild();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
index dca7ca1..f4df3d0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
@@ -22,6 +22,8 @@
 
 import java.util.List;
 
+import javax.annotation.Nullable;
+
 /**
  * Information about the JDK used by the <code>java_*</code> rules.
  *
@@ -33,6 +35,10 @@
 
   private final String sourceVersion;
   private final String targetVersion;
+  // TODO(cushon): remove @Nullable once migration from --javac_bootclasspath and --javac_extdir
+  // is complete, and java_toolchain.{bootclasspath,extclasspath} are mandatory
+  @Nullable private final Iterable<String> bootclasspath;
+  @Nullable private final Iterable<String> extclasspath;
   private final String encoding;
   private final ImmutableList<String> options;
   private final ImmutableList<String> jvmOpts;
@@ -40,12 +46,16 @@
   public JavaToolchainData(
       String sourceVersion,
       String targetVersion,
+      @Nullable Iterable<String> bootclasspath,
+      @Nullable Iterable<String> extclasspath,
       String encoding,
       List<String> xlint,
       List<String> misc,
       List<String> jvmOpts) {
     this.sourceVersion = checkNotNull(sourceVersion, "sourceVersion must not be null");
     this.targetVersion = checkNotNull(targetVersion, "targetVersion must not be null");
+    this.bootclasspath = bootclasspath;
+    this.extclasspath = extclasspath;
     this.encoding = checkNotNull(encoding, "encoding must not be null");
 
     this.jvmOpts = ImmutableList.copyOf(jvmOpts);
@@ -87,6 +97,16 @@
     return targetVersion;
   }
 
+  @Nullable
+  public Iterable<String> getBootclasspath() {
+    return bootclasspath;
+  }
+
+  @Nullable
+  public Iterable<String> getExtclasspath() {
+    return extclasspath;
+  }
+
   public String getEncoding() {
     return encoding;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainDataParser.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainDataParser.java
index 2f4735f..84694a6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainDataParser.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainDataParser.java
@@ -72,6 +72,8 @@
   private static JavaToolchainData parseBuildRuleProto(Build.Rule rule) {
     String source = "";
     String target = "";
+    ImmutableList<String> bootclasspath = ImmutableList.of();
+    ImmutableList<String> extclasspath = ImmutableList.of();
     String encoding = "";
     ImmutableList<String> xlint = ImmutableList.of();
     ImmutableList<String> misc = ImmutableList.of();
@@ -84,6 +86,12 @@
         case "target_version":
           target = attribute.getStringValue();
           break;
+        case "bootclasspath":
+          bootclasspath = ImmutableList.copyOf(attribute.getStringListValueList());
+          break;
+        case "extclasspath":
+          extclasspath = ImmutableList.copyOf(attribute.getStringListValueList());
+          break;
         case "encoding":
           encoding = attribute.getStringValue();
           break;
@@ -98,6 +106,7 @@
           break;
       }
     }
-    return new JavaToolchainData(source, target, encoding, xlint, misc, jvmOpts);
+    return new JavaToolchainData(
+        source, target, bootclasspath, extclasspath, encoding, xlint, misc, jvmOpts);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
index 1457935..8277e68 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
@@ -20,6 +20,9 @@
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.packages.BuildType;
 
@@ -83,8 +86,40 @@
     return javaToolchain.getHeaderCompiler();
   }
 
+  /**
+   * Constructs the compilation bootclasspath.
+   *
+   * @param ruleContext The rule context of the current rule.
+   */
+  public static NestedSet<Artifact> getDefaultBootclasspath(RuleContext ruleContext) {
+    JavaToolchainProvider javaToolchain =
+        ruleContext.getPrerequisite(":java_toolchain", Mode.TARGET, JavaToolchainProvider.class);
+    if (javaToolchain == null) {
+      ruleContext.ruleError("The --java_toolchain option does not point to a java_toolchain rule.");
+      return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+    }
+    return javaToolchain.getBootclasspath();
+  }
+
+  /**
+   * Constructs the compilation extclasspath.
+   *
+   * @param ruleContext The rule context of the current rule.
+   */
+  public static NestedSet<Artifact> getDefaultExtclasspath(RuleContext ruleContext) {
+    JavaToolchainProvider javaToolchain =
+        ruleContext.getPrerequisite(":java_toolchain", Mode.TARGET, JavaToolchainProvider.class);
+    if (javaToolchain == null) {
+      ruleContext.ruleError("The --java_toolchain option does not point to a java_toolchain rule.");
+      return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+    }
+    return javaToolchain.getExtclasspath();
+  }
+
   private final String sourceVersion;
   private final String targetVersion;
+  @Nullable private final NestedSet<Artifact> bootclasspath;
+  @Nullable private final NestedSet<Artifact> extclasspath;
   private final String encoding;
   private final ImmutableList<String> javacOptions;
   private final ImmutableList<String> javacJvmOptions;
@@ -92,11 +127,15 @@
 
   public JavaToolchainProvider(
       JavaToolchainData data,
+      @Nullable NestedSet<Artifact> bootclasspath,
+      @Nullable NestedSet<Artifact> extclasspath,
       List<String> defaultJavacFlags,
       List<String> defaultJavacJvmOpts,
       @Nullable Artifact headerCompiler) {
     this.sourceVersion = checkNotNull(data.getSourceVersion(), "sourceVersion must not be null");
     this.targetVersion = checkNotNull(data.getTargetVersion(), "targetVersion must not be null");
+    this.bootclasspath = bootclasspath;
+    this.extclasspath = extclasspath;
     this.encoding = checkNotNull(data.getEncoding(), "encoding must not be null");
     this.headerCompiler = headerCompiler;
 
@@ -136,12 +175,24 @@
     return targetVersion;
   }
 
+  /** @return the target Java bootclasspath */
+  public NestedSet<Artifact> getBootclasspath() {
+    return bootclasspath;
+  }
+
+  /** @return the target Java extclasspath */
+  public NestedSet<Artifact> getExtclasspath() {
+    return extclasspath;
+  }
+
   /** @return the encoding for Java source files */
+  @Nullable
   public String getEncoding() {
     return encoding;
   }
 
   /** @return the {@link Artifact} of the Header Compiler deploy jar */
+  @Nullable
   public Artifact getHeaderCompiler() {
     return headerCompiler;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
index d1c982c..8cc9623 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
@@ -16,6 +16,7 @@
 import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
 import static com.google.devtools.build.lib.syntax.Type.STRING;
 import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
 
@@ -45,6 +46,16 @@
         should be build.
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
         .add(attr("target_version", STRING).mandatory()) // javac -target flag value.
+        /* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(bootclasspath) -->
+        The Java target exdir entries. Corresponds to javac's -bootclasspath flag.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+        // TODO(cushon): make mandatory once migration from --javac_bootclasspath is complete
+        .add(attr("bootclasspath", LABEL_LIST).cfg(HOST).allowedFileTypes(FileTypeSet.ANY_FILE))
+        /* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(extclasspath) -->
+        The Java target exdir entries. Corresponds to javac's -extdir flag.
+        <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+        // TODO(cushon): make mandatory once migration from --javac_extdir is complete
+        .add(attr("extclasspath", LABEL_LIST).cfg(HOST).allowedFileTypes(FileTypeSet.ANY_FILE))
         /* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(encoding) -->
         The encoding of the java files (e.g., 'UTF-8').
         <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
@@ -95,6 +106,7 @@
     name = "toolchain",
     source_version = "7",
     target_version = "7",
+    bootclasspath = ["//tools/jdk:bootclasspath"],
     encoding = "UTF-8",
     xlint = [ "classfile", "divzero", "empty", "options", "path" ],
     misc = [ "-g" ],