/*
* Copyright 2012 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 com.github.jelmerk;
import org.gradle.BuildAdapter;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.file.FileCollection;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.plugins.BasePlugin;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.plugins.WarPluginConvention;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.javadoc.Javadoc;
import java.io.File;
/**
* Implementation of {@link Plugin} that adds tasks and configuration for generating services using
* <a href="http://www.liferay.com/community/wiki/-/wiki/Main/Service+Builder">Liferay servicebuilder</a>.
* It is implemented as a separate plugin so it can be added to both hooks and portlets
* When you configure this plugin {@link LiferayBasePlugin} is configured as well.
*
* @author Jelmer Kuperus
*/
public class ServiceBuilderPlugin implements Plugin<Project> {
/**
* The name of the task that generates the servicebuilder service.
*/
public static final String GENERATE_SERVICE_TASK_NAME = "generateService";
/**
* The name of the task that generates the javadoc for the service sourceset.
*/
public static final String JAVADOC_SERVICE_TASK_NAME = "javadocService";
/**
* The name of the task that jars up the classes created from the service sourceset.
*/
public static final String JAR_SERVICE_TASK_NAME = "jarService";
/**
* The name of the configuration that holds the classes required to run servicebuilder.
*/
public static final String SERVICE_BUILDER_CONFIGURATION_NAME = "serviceBuilder";
/**
* The name of the sourceset that holds the classes that represent the public api of your servicebuilder service.
*/
public static final String SERVICE_SOURCE_SET_NAME = "service";
/**
* The name of the configuration that holds the classes that are available when the classes of the service sourceset
* are compiled.
*/
public static final String SERVICE_CONFIGURATION_NAME = "service";
/**
* The name of the servicebuilder extension.
*/
public static final String SERVICEBUILDER_EXTENSION_NAME = "servicebuilder";
/**
* {@inheritDoc}
*/
@Override
public void apply(Project project) {
project.getPlugins().apply(LiferayBasePlugin.class);
createServiceSourceSets(project);
createServiceBuilderConfiguration(project);
createServiceConfiguration(project);
createServiceBuilderExtension(project);
configureArchives(project);
configureServiceJavaDoc(project);
configureBuildServiceTaskDefaults(project);
createBuildServiceTask(project);
}
private void createServiceBuilderConfiguration(Project project) {
project.getConfigurations().create(SERVICE_BUILDER_CONFIGURATION_NAME)
.setVisible(false)
.setDescription("The servicebuilder configuration");
}
private void createServiceConfiguration(Project project) {
project.getConfigurations().create(SERVICE_CONFIGURATION_NAME)
.setDescription("The service configuration");
}
private void createServiceBuilderExtension(Project project) {
project.getExtensions().create(SERVICEBUILDER_EXTENSION_NAME, ServiceBuilderPluginExtension.class, project);
}
private void createServiceSourceSets(Project project) {
project.getConvention().getPlugin(JavaPluginConvention.class)
.getSourceSets().create(SERVICE_SOURCE_SET_NAME);
}
private void configureArchives(Project project) {
JavaPluginConvention pluginConvention = project.getConvention().getPlugin(JavaPluginConvention.class);
Jar jar = project.getTasks().create(JAR_SERVICE_TASK_NAME, Jar.class);
jar.setDescription("Assembles a jar archive containing the servicebuilder classes.");
jar.setGroup(BasePlugin.BUILD_GROUP);
jar.from(pluginConvention.getSourceSets().getByName(SERVICE_SOURCE_SET_NAME).getOutput());
jar.setAppendix("service");
project.getArtifacts().add(SERVICE_CONFIGURATION_NAME, project.getTasks().getByName(JAR_SERVICE_TASK_NAME));
}
private void configureBuildServiceTaskDefaults(Project project) {
project.getGradle().addBuildListener(new BuildServiceTaskDefaultsBuildListener(project));
}
private void createBuildServiceTask(Project project) {
BuildService task = project.getTasks().create(GENERATE_SERVICE_TASK_NAME, BuildService.class);
project.getGradle().addBuildListener(new BuildServiceTaskBuildListener(project, task));
task.onlyIf(new BuildServiceTaskOnlyIfSpec());
task.setDescription("Builds a liferay service");
task.setGroup(LiferayBasePlugin.LIFERAY_GROUP_NAME);
}
private void configureServiceJavaDoc(Project project) {
JavaPluginConvention javaConvention = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet serviceSourceSet = javaConvention.getSourceSets().getByName(SERVICE_SOURCE_SET_NAME);
Javadoc serviceJavadoc = project.getTasks().create(JAVADOC_SERVICE_TASK_NAME, Javadoc.class);
serviceJavadoc.setDescription("Generates Javadoc API documentation for the servicebuilder service api.");
serviceJavadoc.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP);
serviceJavadoc.setClasspath(serviceSourceSet.getOutput().plus(serviceSourceSet.getCompileClasspath()));
serviceJavadoc.setDestinationDir(new File(javaConvention.getDocsDir(), "serviceJavadoc"));
serviceJavadoc.setSource(serviceSourceSet.getAllJava());
Javadoc mainJavadoc = (Javadoc) project.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME);
mainJavadoc.dependsOn(serviceJavadoc);
}
private static final class BuildServiceTaskBuildListener extends BuildAdapter {
private final Project project;
private final BuildService task;
private BuildServiceTaskBuildListener(Project project, BuildService task) {
this.project = project;
this.task = task;
}
@Override
public void projectsEvaluated(Gradle gradle) {
WarPluginConvention warConvention = project.getConvention().getPlugin(WarPluginConvention.class);
ServiceBuilderPluginExtension serviceBuilderExtension = project.getExtensions()
.getByType(ServiceBuilderPluginExtension.class);
if (task.getPluginName() == null) {
task.setPluginName(project.getName());
}
if (task.getServiceInputFile() == null) {
task.setServiceInputFile(serviceBuilderExtension.getServiceInputFile());
}
if (task.getJalopyInputFile() == null) {
task.setJalopyInputFile(serviceBuilderExtension.getJalopyInputFile());
}
if (task.getImplSrcDir() == null) {
task.setImplSrcDir(serviceBuilderExtension.getImplSrcDir());
}
if (task.getApiSrcDir() == null) {
task.setApiSrcDir(serviceBuilderExtension.getApiSrcDir());
}
if (task.getResourceDir() == null) {
task.setResourceDir(serviceBuilderExtension.getResourceDir());
}
if (task.getWebappSrcDir() == null) {
task.setWebappDir(warConvention.getWebAppDir());
}
}
}
private static final class BuildServiceTaskDefaultsBuildListener extends BuildAdapter {
private final Project project;
private BuildServiceTaskDefaultsBuildListener(Project project) {
this.project = project;
}
@Override
public void projectsEvaluated(Gradle gradle) {
LiferayPluginExtension liferayExtension = project.getExtensions()
.getByType(LiferayPluginExtension.class);
Configuration servicebuilderConfiguration = project.getConfigurations()
.getByName(SERVICE_BUILDER_CONFIGURATION_NAME);
if (servicebuilderConfiguration.getDependencies().isEmpty()) {
// the sdk dependencies : we will need to download those
DependencyHandler projectDependencies = project.getDependencies();
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, "com.thoughtworks.qdox:qdox:1.12");
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, "jalopy:jalopy:1.5rc3");
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, "javax.servlet:servlet-api:2.5");
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, "javax.servlet.jsp:jsp-api:2.1");
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, "javax.activation:activation:1.1");
// the portal classpath dependencies : we have those locally
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, liferayExtension.getPortalClasspath());
// the common classpath dependencies : we can get from the portal
File appServerGlobalLibDirName = liferayExtension.getAppServerGlobalLibDir();
FileCollection appserverClasspath = project.files(
new File(appServerGlobalLibDirName, "commons-digester.jar"),
new File(appServerGlobalLibDirName, "commons-lang.jar"),
new File(appServerGlobalLibDirName, "easyconf.jar")
);
projectDependencies.add(SERVICE_BUILDER_CONFIGURATION_NAME, appserverClasspath);
}
project.getTasks().withType(BuildService.class,
new SetBuildServiceTaskDefaultsAction(servicebuilderConfiguration));
}
private static final class SetBuildServiceTaskDefaultsAction implements Action<BuildService> {
private final Configuration servicebuilderConfiguration;
private SetBuildServiceTaskDefaultsAction(Configuration servicebuilderConfiguration) {
this.servicebuilderConfiguration = servicebuilderConfiguration;
}
@Override
public void execute(BuildService task) {
if (task.getClasspath() == null) {
task.setClasspath(servicebuilderConfiguration);
}
}
}
}
private static final class BuildServiceTaskOnlyIfSpec implements Spec<Task> {
@Override
public boolean isSatisfiedBy(Task element) {
BuildService castTask = (BuildService) element; //NOSONAR
return castTask.getServiceInputFile().exists();
}
}
}