[NO ISSUE][HYR][LIC] += <extraDependencies/> to license plugin

- Add ability to include extra maven dependencies (i.e. those not in the
  project model) in generated license output
- Extra maven dependencies can be the same groupId/artifactId as an
  exisiting dependency

Change-Id: Ic8f37d0eca6f4e745305b31d74682ca7e62ead27
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/12524
Reviewed-by: Michael Blow <mblow@apache.org>
Reviewed-by: Till Westmann <tillw@apache.org>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterixdb/src/main/appended-resources/supplemental-models.xml b/asterixdb/src/main/appended-resources/supplemental-models.xml
index c352fe5..79ece5e 100644
--- a/asterixdb/src/main/appended-resources/supplemental-models.xml
+++ b/asterixdb/src/main/appended-resources/supplemental-models.xml
@@ -251,8 +251,8 @@
       <properties>
         <!-- fastutil is ALv2, and does not contain any embedded LICENSE or NOTICE file -->
         <!-- see https://github.com/vigna/fastutil/blob/8.5.4/LICENSE-2.0 -->
-        <license.ignoreMissingEmbeddedLicense>8.5.4</license.ignoreMissingEmbeddedLicense>
-        <license.ignoreMissingEmbeddedNotice>8.5.4</license.ignoreMissingEmbeddedNotice>
+        <license.ignoreMissingEmbeddedLicense>8.3.0,8.5.4</license.ignoreMissingEmbeddedLicense>
+        <license.ignoreMissingEmbeddedNotice>8.3.0,8.5.4</license.ignoreMissingEmbeddedNotice>
       </properties>
     </project>
   </supplement>
diff --git a/hyracks-fullstack/hyracks/hyracks-maven-plugins/license-automation-plugin/src/main/java/org/apache/hyracks/maven/license/LicenseMojo.java b/hyracks-fullstack/hyracks/hyracks-maven-plugins/license-automation-plugin/src/main/java/org/apache/hyracks/maven/license/LicenseMojo.java
index 89993fd..2206621 100644
--- a/hyracks-fullstack/hyracks/hyracks-maven-plugins/license-automation-plugin/src/main/java/org/apache/hyracks/maven/license/LicenseMojo.java
+++ b/hyracks-fullstack/hyracks/hyracks-maven-plugins/license-automation-plugin/src/main/java/org/apache/hyracks/maven/license/LicenseMojo.java
@@ -41,13 +41,19 @@
 import java.util.stream.Collectors;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.mutable.MutableBoolean;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hyracks.maven.license.project.LicensedProjects;
 import org.apache.hyracks.maven.license.project.Project;
 import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.DefaultArtifactHandler;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.License;
@@ -121,6 +127,9 @@
     @Parameter
     protected boolean failOnWarning;
 
+    @Parameter
+    protected List<String> extraDependencies = new ArrayList<>();
+
     private Map<String, MavenProject> projectCache = new HashMap<>();
 
     private Map<String, Model> supplementModels;
@@ -393,24 +402,47 @@
     private void gatherProjectDependencies(MavenProject project,
             Map<MavenProject, List<Pair<String, String>>> dependencyLicenseMap,
             Map<String, MavenProject> dependencyGavMap) throws ProjectBuildingException {
-        final Set dependencyArtifacts = project.getArtifacts();
+        final Set<Artifact> dependencyArtifacts = project.getArtifacts();
         if (dependencyArtifacts != null) {
-            for (Object depArtifactObj : dependencyArtifacts) {
-                final Artifact depArtifact = (Artifact) depArtifactObj;
-                if (!excludedScopes.contains(depArtifact.getScope())) {
-                    MavenProject dep = resolveDependency(depArtifact);
-                    dep.setArtifact(depArtifact);
-                    dependencyGavMap.put(toGav(dep), dep);
-                    List<Pair<String, String>> licenseUrls = new ArrayList<>();
-                    for (Object license : dep.getLicenses()) {
-                        final License license1 = (License) license;
-                        String url = license1.getUrl() != null ? license1.getUrl()
-                                : (license1.getName() != null ? license1.getName() : "LICENSE_EMPTY_NAME_URL");
-                        licenseUrls.add(new ImmutablePair<>(url, license1.getName()));
-                    }
-                    dependencyLicenseMap.put(dep, licenseUrls);
+            for (Artifact depArtifact : dependencyArtifacts) {
+                processArtifact(depArtifact, dependencyLicenseMap, dependencyGavMap);
+            }
+        }
+        for (String gav : extraDependencies) {
+            ArtifactHandler handler = new DefaultArtifactHandler("jar");
+            String[] gavParts = StringUtils.split(gav, ':');
+            Artifact manualDep = new DefaultArtifact(gavParts[0], gavParts[1], gavParts[2], Artifact.SCOPE_COMPILE,
+                    "jar", null, handler);
+            processArtifact(manualDep, dependencyLicenseMap, dependencyGavMap);
+        }
+    }
+
+    private void processArtifact(Artifact depArtifact,
+            Map<MavenProject, List<Pair<String, String>>> dependencyLicenseMap,
+            Map<String, MavenProject> dependencyGavMap) throws ProjectBuildingException {
+        if (!excludedScopes.contains(depArtifact.getScope())) {
+            MavenProject dep = resolveDependency(depArtifact);
+            if (!depArtifact.isResolved()) {
+                ArtifactResolutionRequest arr = new ArtifactResolutionRequest();
+                arr.setLocalRepository(localRepository);
+                arr.setRemoteRepositories(remoteRepositories);
+                arr.setArtifact(depArtifact);
+                ArtifactResolutionResult result = artifactResolver.resolve(arr);
+                if (!result.isSuccess()) {
+                    throw new ProjectBuildingException(project.getId(),
+                            "Unable to resolve " + depArtifact + ": " + result.getExceptions(), (Throwable) null);
                 }
             }
+            dep.setArtifact(depArtifact);
+            dependencyGavMap.put(toGav(dep), dep);
+            List<Pair<String, String>> licenseUrls = new ArrayList<>();
+            for (Object license : dep.getLicenses()) {
+                final License license1 = (License) license;
+                String url = license1.getUrl() != null ? license1.getUrl()
+                        : (license1.getName() != null ? license1.getName() : "LICENSE_EMPTY_NAME_URL");
+                licenseUrls.add(new ImmutablePair<>(url, license1.getName()));
+            }
+            dependencyLicenseMap.put(dep, licenseUrls);
         }
     }
 
@@ -430,7 +462,7 @@
                     .get(SupplementalModelHelper.generateSupplementMapKey(depObj.getGroupId(), depObj.getArtifactId()));
             registerVerified(depProj, supplement);
             if (supplement != null) {
-                Model merged = SupplementalModelHelper.mergeModels(assembler, depProj.getModel(), supplement);
+                Model merged = SupplementalModelHelper.mergeModels(assembler, depProj.getModel(), supplement).clone();
                 Set<String> origLicenses =
                         depProj.getModel().getLicenses().stream().map(License::getUrl).collect(Collectors.toSet());
                 Set<String> newLicenses =