code: /**
   * This file is part of Eclipse Steady.
   *
   * 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.
   *
   * SPDX-License-Identifier: Apache-2.0
   * SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
   */
  package org.eclipse.steady.java.gradle;
  
  import com.android.build.gradle.BaseExtension;
  import com.android.build.gradle.api.AndroidSourceSet;
  import org.eclipse.steady.core.util.CoreConfiguration;
  import org.eclipse.steady.goals.AbstractAppGoal;
  import org.eclipse.steady.shared.enums.GoalClient;
  import org.eclipse.steady.shared.json.model.Application;
  import org.eclipse.steady.shared.util.FileUtil;
  import org.eclipse.steady.shared.util.VulasConfiguration;
  
  import org.apache.commons.configuration.ConfigurationException;
  import org.gradle.api.DefaultTask;
  import org.gradle.api.Project;
  import org.gradle.api.plugins.ExtensionContainer;
  import org.gradle.api.plugins.ExtraPropertiesExtension;
  import org.gradle.api.tasks.SourceSet;
  import org.gradle.api.tasks.SourceSetContainer;
  import org.gradle.api.tasks.TaskAction;
  import org.gradle.api.tasks.compile.JavaCompile;
  
  import static org.eclipse.steady.java.gradle.GradleProjectUtilities.*;
  import static org.eclipse.steady.java.gradle.VulasPluginCommon.*;
  
  import java.io.File;
  import java.nio.file.Paths;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  public abstract class AbstractVulasTask extends DefaultTask {
  
    protected Application app = null;
  
    protected AbstractAppGoal goal = null;
    protected Project project = this.getProject();
    protected ProjectOutputTypes projectOutputType;
  
    /** The configuration used throughout the execution of the goal. */
    protected VulasConfiguration vulasConfiguration = new VulasConfiguration();
  
    /**
     * Puts the plugin configuration element <layeredConfiguration> as a new layer into {@link VulasConfiguration}.
     * If no such element exists, e.g., because the POM file does not contain a plugin section for Vulas, default settings
     * are established using {@link MavenProject} and {@link VulasConfiguration#setPropertyIfEmpty(String, Object)}.
     *
     * @throws Exception
     */
    public final void prepareConfiguration() throws Exception {
  
      // Delete any transient settings that remaining from a previous goal execution (if any)
      final boolean contained_values = this.vulasConfiguration.clearTransientProperties();
      if (contained_values) {
        getLogger().info("Transient configuration settings deleted");
      }
  
      // Examining extra properties, if a property starts with "vulas" add it to
      // the configuration as transient property
      ExtraPropertiesExtension ext = project.getExtensions().getExtraProperties();
  
      for (Map.Entry<String, Object> extraProp : ext.getProperties().entrySet()) {
        if (extraProp.getKey().startsWith(VULAS_PLUGIN_NAME)) {
          this.vulasConfiguration.setProperty(extraProp.getKey(), extraProp.getValue());
          getLogger()
              .debug(
                  "Added property to configuration {}={}", extraProp.getKey(), extraProp.getValue());
        }
      }
  
      // Check whether the application context can be established
      try {
        app = CoreConfiguration.getAppContext(this.vulasConfiguration);
      }
      // In case the plugin is called w/o using the Vulas profile, project-specific settings are not
      // set
      // Set them using the project member
      catch (ConfigurationException e) {
  
        this.vulasConfiguration.setProperty(
            CoreConfiguration.APP_CTX_GROUP,
            getMandatoryProjectProperty(project, GradleGavProperty.group, getLogger()));
        this.vulasConfiguration.setProperty(
            CoreConfiguration.APP_CTX_ARTIF,
            getMandatoryProjectProperty(project, GradleGavProperty.name, getLogger()));
        this.vulasConfiguration.setProperty(
            CoreConfiguration.APP_CTX_VERSI,
            getMandatoryProjectProperty(project, GradleGavProperty.version, getLogger()));
        // TODO: packaging is not straightforward with gradle, leave it empty for now
        // VulasConfiguration.setProperty(CoreConfiguration.APP_CTX_PACKA, "", "", true);
        app = CoreConfiguration.getAppContext(this.vulasConfiguration);
      }
  
      String rootDir = project.getProjectDir().getAbsolutePath();
      String buildDir = project.getBuildDir().getAbsolutePath();
  
      // Set defaults for all the paths
      this.vulasConfiguration.setPropertyIfEmpty(
          VulasConfiguration.TMP_DIR, Paths.get(buildDir, "vulas", "tmp").toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.UPLOAD_DIR, Paths.get(buildDir, "vulas", "upload").toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.INSTR_SRC_DIR, Paths.get(rootDir).toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.INSTR_TARGET_DIR, Paths.get(buildDir, "vulas", "target").toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.INSTR_INCLUDE_DIR, Paths.get(buildDir, "vulas", "include").toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.INSTR_LIB_DIR, Paths.get(buildDir, "vulas", "lib").toString());
      this.vulasConfiguration.setPropertyIfEmpty(
          CoreConfiguration.REP_DIR, Paths.get(buildDir, "vulas", "report").toString());
  
      Set<String> appPaths = new HashSet<>();
  
      SourceSetContainer sourceSets;
  
      if (projectOutputType == ProjectOutputTypes.JAR) {
        sourceSets = (SourceSetContainer) project.getProperties().get("sourceSets");
        SourceSet mainSourceSet = sourceSets.getAt("main");
  
        Set<File> sourceDirs = mainSourceSet.getAllJava().getSourceDirectories().getFiles();
        for (File sd : sourceDirs) {
          appPaths.add(sd.getAbsolutePath());
        }
  
        Set<File> outputDirs = mainSourceSet.getOutput().getClassesDirs().getFiles();
        for (File od : outputDirs) {
          appPaths.add(od.getAbsolutePath());
        }
  
      } else if (projectOutputType == ProjectOutputTypes.AAR
          || projectOutputType == ProjectOutputTypes.APK) {
  
        ExtensionContainer e = project.getExtensions();
        BaseExtension ae = (BaseExtension) e.getByName("android");
  
        AndroidSourceSet mainSourceSet = ae.getSourceSets().getByName("main");
  
        Set<File> srcDirs = mainSourceSet.getJava().getSrcDirs();
  
        for (File srcDir : srcDirs) {
          appPaths.add(srcDir.toString());
        }
  
        JavaCompile jc =
            (JavaCompile) project.getTasksByName("compileReleaseJavaWithJavac", true).toArray()[0];
        appPaths.add(jc.getDestinationDir().toString());
      }
  
      String strAppPaths = String.join(",", appPaths);
      getLogger().quiet("App paths: {}", strAppPaths);
  
      this.vulasConfiguration.setPropertyIfEmpty(CoreConfiguration.APP_DIRS, strAppPaths);
  
      getLogger()
          .info("Top level project: " + project.getRootProject().getBuildFile().getAbsolutePath());
      getLogger().info("Execution root dir: " + project.getRootProject().getProjectDir());
  
      this.vulasConfiguration.log(new String[] {VULAS_PLUGIN_NAME}, "    ");
    }
  
    @TaskAction
    public final void executeTask() throws Exception {
  
      projectOutputType = determineProjectOutputType(this.project, getLogger());
  
      this.prepareConfiguration();
      this.createGoal();
      this.goal.setGoalClient(GoalClient.GRADLE_PLUGIN);
      this.goal.setConfiguration(this.vulasConfiguration);
  
      // Set the application paths
      this.goal.addAppPaths(
          FileUtil.getPaths(
              this.vulasConfiguration.getStringArray(CoreConfiguration.APP_DIRS, null)));
  
      this.executeGoal();
    }
  
    protected abstract void createGoal();
  
    protected void executeGoal() throws Exception {
      this.goal.executeSync();
    }
  }
  