/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.language.java.plugins;
import com.google.common.collect.ImmutableSet;
import org.gradle.api.DefaultTask;
import org.gradle.api.Incubating;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
import org.gradle.api.internal.attributes.AttributesSchemaInternal;
import org.gradle.internal.Transformers;
import org.gradle.internal.operations.BuildOperationExecutor;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.jvm.JvmByteCode;
import org.gradle.jvm.internal.JarBinarySpecInternal;
import org.gradle.jvm.internal.JvmAssembly;
import org.gradle.jvm.internal.WithDependencies;
import org.gradle.jvm.internal.WithJvmAssembly;
import org.gradle.jvm.internal.resolve.DefaultVariantsMetaData;
import org.gradle.jvm.internal.resolve.SourceSetDependencyResolvingClasspath;
import org.gradle.jvm.internal.resolve.VariantsMetaData;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.language.base.DependentSourceSet;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
import org.gradle.language.base.internal.registry.LanguageTransform;
import org.gradle.language.base.internal.registry.LanguageTransformContainer;
import org.gradle.language.base.plugins.ComponentModelBasePlugin;
import org.gradle.language.java.JavaSourceSet;
import org.gradle.language.java.internal.DefaultJavaLanguageSourceSet;
import org.gradle.language.java.tasks.PlatformJavaCompile;
import org.gradle.language.jvm.plugins.JvmResourcesPlugin;
import org.gradle.model.Mutate;
import org.gradle.model.RuleSource;
import org.gradle.model.internal.manage.schema.ModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.platform.base.BinarySpec;
import org.gradle.platform.base.ComponentType;
import org.gradle.platform.base.DependencySpec;
import org.gradle.platform.base.TypeBuilder;
import org.gradle.platform.base.internal.BinarySpecInternal;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Iterables.concat;
import static org.gradle.util.CollectionUtils.collect;
import static org.gradle.util.CollectionUtils.first;
/**
* Plugin for compiling Java code. Applies the {@link org.gradle.language.base.plugins.ComponentModelBasePlugin} and {@link org.gradle.language.jvm.plugins.JvmResourcesPlugin}. Registers "java"
* language support with the {@link JavaSourceSet}.
*
* @since 3.4
*/
@Incubating
public class JavaLanguagePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPluginManager().apply(ComponentModelBasePlugin.class);
project.getPluginManager().apply(JvmResourcesPlugin.class);
}
@SuppressWarnings("UnusedDeclaration")
static class Rules extends RuleSource {
@ComponentType
void registerLanguage(TypeBuilder<JavaSourceSet> builder) {
builder.defaultImplementation(DefaultJavaLanguageSourceSet.class);
}
@Mutate
void registerLanguageTransform(LanguageTransformContainer languages, ServiceRegistry serviceRegistry) {
ModelSchemaStore schemaStore = serviceRegistry.get(ModelSchemaStore.class);
languages.add(new Java(schemaStore));
}
}
/**
* The language transform implementation for Java sources.
*/
private static class Java implements LanguageTransform<JavaSourceSet, JvmByteCode> {
private final JavaSourceTransformTaskConfig config;
public Java(ModelSchemaStore schemaStore) {
this.config = new JavaSourceTransformTaskConfig(schemaStore);
}
@Override
public String getLanguageName() {
return "java";
}
@Override
public Class<JavaSourceSet> getSourceSetType() {
return JavaSourceSet.class;
}
@Override
public Map<String, Class<?>> getBinaryTools() {
return Collections.emptyMap();
}
@Override
public Class<JvmByteCode> getOutputType() {
return JvmByteCode.class;
}
@Override
public SourceTransformTaskConfig getTransformTask() {
return config;
}
@Override
public boolean applyToBinary(BinarySpec binary) {
return binary instanceof WithJvmAssembly;
}
private static class JavaSourceTransformTaskConfig implements SourceTransformTaskConfig {
private final ModelSchemaStore schemaStore;
private JavaSourceTransformTaskConfig(ModelSchemaStore schemaStore) {
this.schemaStore = schemaStore;
}
@Override
public String getTaskPrefix() {
return "compile";
}
@Override
public Class<? extends DefaultTask> getTaskType() {
return PlatformJavaCompile.class;
}
@Override
public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
final PlatformJavaCompile compile = (PlatformJavaCompile) task;
JavaSourceSet javaSourceSet = (JavaSourceSet) sourceSet;
JvmAssembly assembly = ((WithJvmAssembly) binary).getAssembly();
assembly.builtBy(compile);
compile.setDescription("Compiles " + javaSourceSet + ".");
compile.setDestinationDir(conventionalCompilationOutputDirFor(assembly));
compile.dependsOn(javaSourceSet);
compile.setSource(javaSourceSet.getSource());
JavaPlatform targetPlatform = assembly.getTargetPlatform();
String targetCompatibility = targetPlatform.getTargetCompatibility().toString();
compile.setPlatform(targetPlatform);
compile.setToolChain(assembly.getToolChain());
compile.setTargetCompatibility(targetCompatibility);
compile.setSourceCompatibility(targetCompatibility);
SourceSetDependencyResolvingClasspath classpath = classpathFor(binary, javaSourceSet, serviceRegistry, schemaStore);
compile.setClasspath(classpath);
}
private static File conventionalCompilationOutputDirFor(JvmAssembly assembly) {
return first(assembly.getClassDirectories());
}
private static SourceSetDependencyResolvingClasspath classpathFor(BinarySpec binary, JavaSourceSet javaSourceSet, ServiceRegistry serviceRegistry, ModelSchemaStore schemaStore) {
Iterable<DependencySpec> dependencies = compileDependencies(binary, javaSourceSet);
ArtifactDependencyResolver dependencyResolver = serviceRegistry.get(ArtifactDependencyResolver.class);
RepositoryHandler repositories = serviceRegistry.get(RepositoryHandler.class);
List<ResolutionAwareRepository> resolutionAwareRepositories = collect(repositories, Transformers.cast(ResolutionAwareRepository.class));
ModelSchema<? extends BinarySpec> schema = schemaStore.getSchema(((BinarySpecInternal) binary).getPublicType());
VariantsMetaData variantsMetaData = DefaultVariantsMetaData.extractFrom(binary, schema);
AttributesSchemaInternal attributesSchema = serviceRegistry.get(AttributesSchemaInternal.class);
ImmutableModuleIdentifierFactory moduleIdentifierFactory = serviceRegistry.get(ImmutableModuleIdentifierFactory.class);
BuildOperationExecutor buildOperationExecutor = serviceRegistry.get(BuildOperationExecutor.class);
return new SourceSetDependencyResolvingClasspath((BinarySpecInternal) binary, javaSourceSet, dependencies, dependencyResolver, variantsMetaData, resolutionAwareRepositories, attributesSchema, moduleIdentifierFactory, buildOperationExecutor);
}
private static Iterable<DependencySpec> compileDependencies(BinarySpec binary, DependentSourceSet sourceSet) {
return concat(
sourceSet.getDependencies().getDependencies(),
componentDependenciesOf(binary),
apiDependenciesOf(binary));
}
private static Iterable<DependencySpec> componentDependenciesOf(BinarySpec binary) {
return binary instanceof WithDependencies
? ((WithDependencies) binary).getDependencies()
: NO_DEPENDENCIES;
}
private static Iterable<DependencySpec> apiDependenciesOf(BinarySpec binary) {
return binary instanceof JarBinarySpecInternal
? ((JarBinarySpecInternal) binary).getApiDependencies()
: NO_DEPENDENCIES;
}
private static final Iterable<DependencySpec> NO_DEPENDENCIES = ImmutableSet.of();
}
}
}