[java-identity-provider] branch main updated: JPAR-176 Parse the child modules in idp-parent

Rod Widdowson rdw at steadingsoftware.com
Fri Jun 25 15:06:44 UTC 2021


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=6b90b71ffa3ff1ea4da33dbba91cb5b6cdf7a744

The following commit(s) were added to refs/heads/main by this push:
       new  6b90b71ff JPAR-176 Parse the child modules in idp-parent
6b90b71ff is described below

commit 6b90b71ffa3ff1ea4da33dbba91cb5b6cdf7a744
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Jun 24 12:58:45 2021 +0100

    JPAR-176 Parse the child modules in idp-parent
    
    https://issues.shibboleth.net/jira/browse/JPAR-176
    
    This actually simplifies the reproting (as well as making it 'honest'.
---
 .../idp/dependencies/DependencyTest.java           | 190 +++++++++---------
 .../net/shibboleth/idp/dependencies/ParsedPom.java | 220 +++++++++++++++------
 .../net/shibboleth/idp/dependencies/PomLoader.java |  36 ++++
 3 files changed, 290 insertions(+), 156 deletions(-)

diff --git a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
index 50a4af684..266048397 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/DependencyTest.java
@@ -58,12 +58,11 @@ import net.shibboleth.idp.dependencies.ParsedPom.PomArtifact;
 import net.shibboleth.idp.installer.plugin.impl.PluginInstallerSupport;
 import net.shibboleth.utilities.java.support.collection.Pair;
 import net.shibboleth.utilities.java.support.xml.ParserPool;
-import net.shibboleth.utilities.java.support.xml.XMLParserException;
 
 /**
  * Test that what we see is what we wanted in abuild - we do this by reading the pom
  */
-public class DependencyTest extends OpenSAMLInitBaseTestCase {
+public class DependencyTest extends OpenSAMLInitBaseTestCase implements PomLoader {
 
     /** Set this up if you want to run the tests from eclipse. */
     private static String LOCAL_MAVEN_HOME = null;
@@ -77,18 +76,15 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
     /** Work space.  Deleted on exit. */
     private Path workingDir;
     
-    /** The project parent dependencies */
-    private List<PomArtifact> dependencies = new ArrayList<>();
-    
-    /** The IDP Version/artifact info */
-    private PomArtifact idpArtefact;
+    /** The parsed idp-parent pom. */
+    private ParsedPom idpParent;
     
     private PrintWriter report;
 
     private PomArtifact parentArtefact;
     
     /**  We have as an assumption that the CWD is idp-installer.  Test this.
-     * @throws IOException if the directorty isn't what we expect it to be, 
+     * @throws IOException if the directory isn't what we expect it to be
      */
     @BeforeClass public void testWorkingDir() throws IOException {
         final Path path = Path.of(".");
@@ -121,61 +117,57 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
         System.setProperty("maven.home", home);
     }
     
-    /** Set up the environment for running the test.
-     * Parse the IdP parent pom.
-     * From that find the description of parent pom & download it.
-     * Parse that.
-     * @throws IOException if a folder or files has issues
-     * @throws XMLParserException if the pom is badly formed
-     * @throws MavenInvocationException if maven fails
+    /** Parse the idp-parent pom and all related.
+     * @throws Exception if a folder or files has issues, 
+     *    if the pom is badly formed, or if the download fails
      */
 
-    @BeforeClass(dependsOnMethods = {"setupMavenEnvironment", "testWorkingDir"}) public void setup() throws IOException, XMLParserException, MavenInvocationException {
+    @BeforeClass(dependsOnMethods = {"setupMavenEnvironment", "testWorkingDir"}) public void parsePom() throws Exception {
         workingDir = Files.createTempDirectory("dependencyTest");
         parserPool = XMLObjectProviderRegistrySupport.getParserPool();
-        ParsedPom idpParent = new ParsedPom(parserPool, Path.of("../idp-parent/pom.xml"), "idp-parent/pom.xml", null, Collections.emptyList());
-        idpArtefact = idpParent.getOurInfo();
+
+        idpParent = new ParsedPom(parserPool, this, Path.of("../idp-parent/pom.xml"), "idp-parent/pom.xml", null, Collections.emptyMap());
         parentArtefact = idpParent.getParent(); 
         assertNotNull(parentArtefact);
         final Path parentPath = downloadPom(parentArtefact);
-        final Set<PomArtifact> allManagedDeps = new HashSet<>();
-        final ParsedPom projectParent = new ParsedPom(parserPool, parentPath, "parent/pom.xml", new Properties(), Collections.emptyList());
-        allManagedDeps.addAll(projectParent.getManagedDependencies());
-        idpParent = new ParsedPom(parserPool, Path.of("../idp-parent/pom.xml"), "idp-parent/pom.xml", projectParent.getProperties(), projectParent.getCompileDependencies());
-        allManagedDeps.addAll(idpParent.getManagedDependencies());
-        dependencies.addAll(projectParent.getCompileDependencies());
-        dependencies.addAll(idpParent.getCompileDependencies());
-        for (final PomArtifact bom : projectParent.getBomDependencies()) {
-            final Path bomPath = downloadPom(bom);
-            final ParsedPom bomContents = new ParsedPom(parserPool, bomPath, bom.getArtifactId()+".pom", projectParent.getProperties(), projectParent.getCompileDependencies());
-            dependencies.addAll(bomContents.getCompileDependencies());
-            allManagedDeps.addAll(bomContents.getManagedDependencies());
-        }
-        for (final PomArtifact bom : idpParent.getBomDependencies()) {
-            final Path bomPath = downloadPom(bom);
-            final ParsedPom bomContents = new ParsedPom(parserPool, bomPath, bom.getArtifactId()+".pom", projectParent.getProperties(), projectParent.getCompileDependencies());
-            dependencies.addAll(bomContents.getCompileDependencies());
-            allManagedDeps.addAll(bomContents.getManagedDependencies());
-        }
-        final ParsedPom warDist = new ParsedPom(parserPool, Path.of("../idp-war-distribution/pom.xml"), "idp-war-distribution/pom.xml", projectParent.getProperties(), allManagedDeps);
-        dependencies.addAll(warDist.getRuntimeDependencies());
+        final ParsedPom projectParent = new ParsedPom(parserPool, this, parentPath, "parent/pom.xml", new Properties(), Collections.emptyMap());
+        idpParent = new ParsedPom(parserPool, this, Path.of("../idp-parent/pom.xml"), "idp-parent/pom.xml", projectParent.getProperties(), projectParent.getManagedDependencies());
+        assertTrue(projectParent.getCompileDependencies().isEmpty(), "project parent contributes compile dependencies");
+        assertTrue(projectParent.getRuntimeDependencies().isEmpty(), "project parent contributes run time dependencies");
+    }
+
+    /** Create the reporter print stream
+     * @throws FileNotFoundException  if we cannot
+     */
+    @BeforeClass(dependsOnMethods = {"testWorkingDir"}) public void initializeOutput() throws FileNotFoundException {
         final File out = new File("target/dependencyReport.txt");
         final FileOutputStream outStream = new FileOutputStream(out);
         report = new PrintWriter(new BufferedOutputStream(outStream));
         report.format("Dependency Analysis, started at %s\n", Instant.now().toString());
     }
-    
+
     /** Clean up after ourselves. */
     @AfterClass public void teardown() {
         PluginInstallerSupport.deleteTree(workingDir);
     }
-    
+
     /** The guts of the first test.  Are all the files what we expected?
      * @throws IOException if the file doesn't exist
      * @throws MavenInvocationException if we fail to download a pom or a dependency
      */
-    @Test(enabled=false) public void testDependencies() throws IOException, MavenInvocationException {
-        final Path lib = Path.of("../idp-war-distribution/target/idp-war-distribution-"+ idpArtefact.getVersion()).resolve("WEB-INF").resolve("lib");
+    @Test(enabled=true) public void testDependencies() throws IOException, MavenInvocationException {
+        if (!idpParent.getDuplicates().isEmpty()) {
+            report.format("Duplicates found parsing the poms\n");
+            for (final Pair<PomArtifact,PomArtifact> poms : idpParent.getDuplicates()) {
+                final PomArtifact f = poms.getFirst();
+                final PomArtifact s = poms.getSecond();
+
+                report.format("%-22s\t: %s (from %s) and %s (from %s)\n", f.getMapKey(),
+                        f.getVersion(), f.getSourcePomFilename(),
+                        s.getVersion(), s.getSourcePomFilename());
+            }
+        }
+        final Path lib = Path.of("../idp-war-distribution/target/idp-war-distribution-"+ idpParent.getOurInfo().getVersion()).resolve("WEB-INF").resolve("lib");
         assertTrue(Files.exists(lib), "idp-war must have been built");
         final Map<String, String> names = new HashMap<>();
         int wrongVersion = 0;
@@ -183,7 +175,11 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
         int nonUsed = 0;
         int dupNames = 0;
         final int similarNames = Files.list(lib).mapToInt(e -> addName(names, lib.relativize(e).toString())).sum();
-        report.format("WAR CONTENTS\n=== ========\n");
+        report.format("Dependencies found in war file\n\n");
+
+        List<PomArtifact> dependencies = new ArrayList<>(idpParent.getCompileDependencies().size() + idpParent.getRuntimeDependencies().size());
+        dependencies.addAll(idpParent.getCompileDependencies());
+        dependencies.addAll(idpParent.getRuntimeDependencies());
         Collections.sort(dependencies);
         // ArtifactId->(Ver->[source, source])
         final Map<String, Map<String, Set<String>>> dependencySource = new HashMap<>();
@@ -193,8 +189,12 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
             final String ver = artifact.getVersion();
             final String sourcePomFilename = "(from " + artifact.getSourcePomFilename() + ")";
             final String version = names.remove(id);
-            if (artifact.equals(last)) {
-                report.format("%-22s\t: %-12s\tDuplicate artifact: %-22s\n", id, ver, sourcePomFilename);
+            if (idpParent.getGeneratedArtifacts().contains(artifact)) {
+                if (!artifact.equals(last)) {
+                    report.format("%-22s\t: %-12s\tGenerated by parent war\n", id, ver);
+                }
+            } else if (artifact.equals(last)) {
+                report.format("%-22s\t: %-12s\tRuntime & Compile: %-22s\n", id, ver, sourcePomFilename);
                 dupNames++;
             } else if (version == null) {
                 report.format("%-22s\t: %-12s\tNot found in war    %-22s\n", id, ver, sourcePomFilename);
@@ -223,7 +223,9 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
 
         final List<String> contributedDeps = new ArrayList<>(names.keySet());
         Collections.sort(contributedDeps);
-        int noSource = 0, verMismatch = 0;
+        int noSource = 0;
+
+        report.format("Found in but not explicitly defined as a dependency:\n\n");
 
         for (final String dependency: contributedDeps) {
             final Map<String, Set<String>> map = dependencySource.get(dependency);
@@ -237,7 +239,7 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
                 final Set<String> sources = map.remove(version);
                 if (sources == null) {
                     report.format("%-22s\t: %-12s\tNO Dependency contributes this version\n", dependency, version);
-                    verMismatch ++;
+                    noSource ++;
                 } else {
                     reportContributions(dependency, version, sources);
                 }
@@ -248,12 +250,16 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
                 }
             }
         }
-        report.format("%d Version mismatches, %d lost artifacts\n", verMismatch, noSource);
+        report.format("%d Orphans artifact(s)\n", noSource);
+        report.format("%d Similar artifact names(s)\n", similarNames);
+        report.format("%d Wrong Versions(s)\n", wrongVersion);
         report.format("Completed at %s\n", Instant.now().toString());
         report.flush();
         report.close();
         assertEquals(wrongVersion,  0, "Mismatched version");
         assertEquals(similarNames,  0, "Multiple similarly named jars");
+        assertEquals(noSource,  0, "Orphaned Artefacts");
+        assertTrue(idpParent.getDuplicates().isEmpty(), "Duplicate dependencies");
     }
     
     /** report the contributions of the provided dependency & version.
@@ -340,47 +346,47 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
                 .append(artifact.getVersion())
                 .append(".xml").
                 toString()).toFile();
-        final FileOutputStream outStream = new FileOutputStream(file);
-        final PrintWriter pom = new PrintWriter(new BufferedOutputStream(outStream));
-        pom.format("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
-                + "     xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
-                + "    <modelVersion>4.0.0</modelVersion>\n"
-                + "\n"
-                + "    <parent>\n"
-                + "        <groupId>%s</groupId>\n"
-                + "        <artifactId>%s</artifactId>\n"
-                + "        <version>%s</version>\n"
-                + "    </parent>\n"
-                + "\n", parentArtefact.getGroupId(), parentArtefact.getArtifactId(), parentArtefact.getVersion());
-        pom.format("    <groupId>shibboleth.net.dependency</groupId>\n"
-                + "    <version>0.0.1</version>\n"
-                + "    <name>Shibboleth Dependency</name>\n"
-                + "    <artifactId>idp-dep-%s</artifactId>\n"
-                + "    <packaging>jar</packaging>\n\n", artifact.getArtifactId());
-        pom.format("    <dependencies>\n"
-                + "    <dependency>\n"
-                + "            <groupId>%s</groupId><artifactId>%s</artifactId><version>%s</version>\n"
-                + "    </dependency>\n"
-                + "    </dependencies>\n\n", artifact.getGroupId(),artifact.getArtifactId(), artifact.getVersion());
-        pom.format("    <repositories>\n"
-                + "        <repository>\n"
-                + "            <id>shib-release</id>\n"
-                + "            <url>https://build.shibboleth.net/nexus/content/groups/public</url>\n"
-                + "            <snapshots>\n"
-                + "                <enabled>false</enabled>\n"
-                + "            </snapshots>\n"
-                + "        </repository>\n"
-                + "        <repository>\n"
-                + "            <id>shib-snapshot</id>\n"
-                + "            <url>https://build.shibboleth.net/nexus/content/repositories/snapshots</url>\n"
-                + "            <releases>\n"
-                + "                <enabled>false</enabled>\n"
-                + "            </releases>\n"
-                + "        </repository>\n"
-                + "    </repositories>\n"
-                + "</project>\n");
-        pom.flush();
-        pom.close();
+        try (final PrintWriter pom = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)))) {
+            pom.format("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+                    + "     xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
+                    + "    <modelVersion>4.0.0</modelVersion>\n"
+                    + "\n"
+                    + "    <parent>\n"
+                    + "        <groupId>%s</groupId>\n"
+                    + "        <artifactId>%s</artifactId>\n"
+                    + "        <version>%s</version>\n"
+                    + "    </parent>\n"
+                    + "\n", parentArtefact.getGroupId(), parentArtefact.getArtifactId(), parentArtefact.getVersion());
+            pom.format("    <groupId>shibboleth.net.dependency</groupId>\n"
+                    + "    <version>0.0.1</version>\n"
+                    + "    <name>Shibboleth Dependency</name>\n"
+                    + "    <artifactId>idp-dep-%s</artifactId>\n"
+                    + "    <packaging>jar</packaging>\n\n", artifact.getArtifactId());
+            pom.format("    <dependencies>\n"
+                    + "    <dependency>\n"
+                    + "            <groupId>%s</groupId><artifactId>%s</artifactId><version>%s</version>\n"
+                    + "    </dependency>\n"
+                    + "    </dependencies>\n\n", artifact.getGroupId(),artifact.getArtifactId(), artifact.getVersion());
+            pom.format("    <repositories>\n"
+                    + "        <repository>\n"
+                    + "            <id>shib-release</id>\n"
+                    + "            <url>https://build.shibboleth.net/nexus/content/groups/public</url>\n"
+                    + "            <snapshots>\n"
+                    + "                <enabled>false</enabled>\n"
+                    + "            </snapshots>\n"
+                    + "        </repository>\n"
+                    + "        <repository>\n"
+                    + "            <id>shib-snapshot</id>\n"
+                    + "            <url>https://build.shibboleth.net/nexus/content/repositories/snapshots</url>\n"
+                    + "            <releases>\n"
+                    + "                <enabled>false</enabled>\n"
+                    + "            </releases>\n"
+                    + "        </repository>\n"
+                    + "    </repositories>\n"
+                    + "</project>\n");
+            pom.flush();
+            pom.close();
+        }
         return file;
     }
 
@@ -421,12 +427,12 @@ public class DependencyTest extends OpenSAMLInitBaseTestCase {
         return 1;
     }
 
-    /** tell maven to download the artifact and returns it's path.
+    /** Tell Maven to download the artifact and returns it's path.
      * @param artifact what to look for
      * @return the pom as a {@link Path}
      * @throws MavenInvocationException if the download failed
      */
-    private Path downloadPom(final PomArtifact artifact) throws MavenInvocationException {
+    public Path downloadPom(final PomArtifact artifact) throws MavenInvocationException {
         final Path output =  workingDir.resolve(artifact.getArtifactId() + ".pom");
         assertFalse(Files.exists(output));
         final String fullArtifactName = new StringBuilder(artifact.getGroupId())
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
index b06800588..ba0bc12f6 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/ParsedPom.java
@@ -19,20 +19,19 @@ package net.shibboleth.idp.dependencies;
 
 import java.io.BufferedInputStream;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 
@@ -55,19 +54,22 @@ import net.shibboleth.utilities.java.support.xml.XMLParserException;
 public class ParsedPom extends OpenSAMLInitBaseTestCase{
     
     /** Compile dependencies - what we care about. */
-    private final List<PomArtifact> compileDependencies = new ArrayList<>();
+    private final Map<String, PomArtifact> compileDependencies = new HashMap<>();
     
     /** BOM dependencies. */
-    private final List<PomArtifact> bomDependencies = new ArrayList<>();
+    private final Map<String, PomArtifact> bomDependencies = new HashMap<>();
 
-    /** Rumtime dependencies. */
-    private final List<PomArtifact> runtimeDependencies = new ArrayList<>();    
+    /** Rum time dependencies. */
+    private final Map<String, PomArtifact> runtimeDependencies = new HashMap<>();    
+
+    /** Duplicate dependencies. */
+    private final List<Pair<PomArtifact,PomArtifact>> duplicates = new ArrayList<>();    
+
+    /** Generated artifacts. */
+    private final Set<PomArtifact> generated = new HashSet<>();
 
-    /** managed dependencies. */
-    private final List<PomArtifact> myManagedDependencies = new ArrayList<>();    
-    
     /** Inherits dependencies. */
-    private final Map<String, PomArtifact> inputManagedDependencies;
+    private final Map<String, PomArtifact> managedDependencies;
     
     /** Which the POM.*/
     @Nonnull private final String sourcePomInfo;
@@ -85,24 +87,24 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
      * Constructor.
      *
      * @param parsers a short-cut to let us parse XML
+     * @param pomLoader how to get a pom (for BOM loading)
      * @param pom the {@link Path} to the pom.
      * @param pomName an ID for the pom
      * @param parentPomProperties if present it is properties from the parent (which might be empty), if null we are *only*
      * looking for the parent pom coordinates.
-     * @param managed Managed dependencies from parent
-     * @throws IOException from parsing
-     * @throws FileNotFoundException if the file doesn't exist
-     * @throws XMLParserException from parsing
+     * @param map Managed dependencies from parent
+     * @throws Exception if we have issued locating a bom
      */
     public ParsedPom(@Nonnull final ParserPool parsers,
+                     @Nonnull final PomLoader pomLoader,
                      @Nonnull final Path pom,
                      @Nonnull final String pomName,
                      @Nullable final Properties parentPomProperties, 
-                     @Nonnull final Collection<PomArtifact> managed)
-            throws FileNotFoundException, IOException, XMLParserException {
+                     @Nonnull final Map<String, PomArtifact> map)
+            throws Exception {
+
+        managedDependencies = new HashMap<>(map);
 
-        inputManagedDependencies = managed.stream().collect(Collectors.toMap(e->e.getGroupId()+"+"+e.getArtifactId(), Function.identity()));
-                
         sourcePomInfo = pomName;
         Document document;
         try (final InputStream stream = new BufferedInputStream(new FileInputStream(pom.toFile()))) {
@@ -128,43 +130,82 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
             String pName = (String) p;
             properties.setProperty(pName, parentPomProperties.getProperty(pName));
         }
+        properties.setProperty("project.basedir", "<bogus_base_dir>");
+        properties.setProperty("project.build.directory", "<bogus_build_dir>");
+        properties.setProperty("project.version", us.getVersion());
+        properties.setProperty("project.groupId", us.getGroupId());
+        properties.setProperty("project.artifactId", us.getArtifactId());
+
         final List<Element> props = ElementSupport.getChildElementsByTagName(el, "properties");
         if (!props.isEmpty()) {
             parseProperties(props.get(0));
         }
-        if (!properties.contains("project.groupId") && parent != null) {
-            properties.setProperty("project.groupId", parent.groupId);
+
+        for (final Element dependencyMgt: ElementSupport.getChildElementsByTagName(el, "dependencyManagement")) {
+            for (final Element dependencies : ElementSupport.getChildElementsByTagName(dependencyMgt, "dependencies")) {
+                parseManagedDependencies(dependencies);
+            }
         }
-        if (!properties.contains("project.version") && parent != null) {
-            properties.setProperty("project.version", parent.version);
+        for (final PomArtifact bom : bomDependencies.values()) {
+            final ParsedPom parsedBom = new ParsedPom(parsers, pomLoader, pomLoader.downloadPom(bom), bom.toString(), new Properties(), Collections.emptyMap());
+            for (PomArtifact dep : parsedBom.getManagedDependencies().values()) {
+                addWithCheck(dep, managedDependencies);
+            }
         }
-        final List<Element> dependencyMgt = ElementSupport.getChildElementsByTagName(el, "dependencyManagement");
-        if (!dependencyMgt.isEmpty()) {
-            final List<Element> dependencies = ElementSupport.getChildElementsByTagName(dependencyMgt.get(0), "dependencies");
-            parseDependencies(dependencies.get(0), true);
+
+        for (final Element dependencies : ElementSupport.getChildElementsByTagName(el, "dependencies")) {
+            parseDependencies(dependencies);
         }
-        final List<Element> dependencies = ElementSupport.getChildElementsByTagName(el, "dependencies");
-        if (!dependencies.isEmpty()) {
-            parseDependencies(dependencies.get(0), false);
+
+        final Set<PomArtifact> moduleCompiles = new HashSet<>();
+        final Set<PomArtifact> moduleRuntimes = new HashSet<>();
+        for (final Element modules: ElementSupport.getChildElementsByTagName(el, "modules")) {
+            for (final Element module: ElementSupport.getChildElementsByTagName(modules, "module")) {
+                // Kludge for Jackson
+                final Path modulePath = Path.of(module.getTextContent()).resolve("pom.xml");
+                if (Files.exists(modulePath)) {
+                    final ParsedPom modulePom = new ParsedPom(parsers, pomLoader, modulePath ,module.getTextContent(), properties, managedDependencies);
+                    moduleCompiles.addAll(modulePom.getCompileDependencies());
+                    moduleRuntimes.addAll(modulePom.getRuntimeDependencies());
+                    generated.add(modulePom.getOurInfo());
+                }
+            }
+        }
+        for (final PomArtifact dep : moduleCompiles) {
+            addWithCheck(dep, compileDependencies);
+        }
+        for (final PomArtifact dep : moduleRuntimes) {
+            addWithCheck(dep, runtimeDependencies);
         }
     }
 
+    /** Get the text content of the element, performing property replacement as we go.
+     * @param el the element
+     * @return the value, with property replacement.
+     */
     @Nonnull protected String getElementContent(final Element el) {
-        String contents = StringSupport.trimOrNull(el.getTextContent());
-        contents = Constraint.isNotNull(contents, "<" + el.getLocalName() +  "> must have content");
-        // Not perfect matching but fits our needs
-        if (contents.length() > 3 && contents.startsWith("${") && contents.endsWith("}")) {
-            final String propName = contents.substring(2, contents.length()-1);
-            contents = Constraint.isNotNull(properties.getProperty(propName), propName + " is not defined");
+        String remainingContents = StringSupport.trimOrNull(el.getTextContent());
+        remainingContents = Constraint.isNotNull(remainingContents, "<" + el.getLocalName() +  "> must have content");
+        final StringBuilder contents = new StringBuilder();
+        for (int index = remainingContents.indexOf("${"); index >= 0; index = remainingContents.indexOf("${")) {
+            contents.append(remainingContents.substring(0, index));
+            remainingContents = remainingContents.substring(index);
+            final int endIndex = remainingContents.indexOf("}");
+            if (endIndex <= 1) {
+                break;
+            }
+            final String propName = remainingContents.substring(2, endIndex);
+            contents.append(Constraint.isNotNull(properties.getProperty(propName), propName + " is not defined"));
+            remainingContents = remainingContents.substring(endIndex+1);
         }
-        return contents;
+        contents.append(remainingContents);
+        return contents.toString();
     }
 
-    /**
+    /** Parse the dependency part of the pom.
      * @param item what to parse
-     * @param isManaged to we add to the managed dependencies?
      */
-    private void parseDependencies(final Element item, final boolean isManaged) {
+    private void parseDependencies(final Element item) {
         final List<Element> dependencies = ElementSupport.getChildElementsByTagName(item, "dependency");
         
         for (Element dependency : dependencies) {
@@ -173,21 +214,18 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
             if (!types.isEmpty()) {
                 final String type = StringSupport.trimOrNull(types.get(0).getTextContent());
                 if ("pom".equals(type)) {
-                    bomDependencies.add(artifact);
+                    addWithCheck(artifact, bomDependencies);
                     continue;
                 } else if (!"jar".equals(type)) {
                     // not for us
                     continue;
                 }                
             }
-            if (isManaged) {
-                myManagedDependencies.add(artifact);
-            }
             final List<Element> scopes = ElementSupport.getChildElementsByTagName(dependency, "scope");
             if (!scopes.isEmpty()) {
                 final String scope = StringSupport.trimOrNull(scopes.get(0).getTextContent());
                 if ("runtime".equals(scope)) {
-                    runtimeDependencies.add(artifact);
+                    addWithCheck(artifact, runtimeDependencies);
                     continue;
                 }
                 if (!"compile".equals(scope)) {
@@ -195,7 +233,41 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
                     continue;
                 }
             }
-            compileDependencies.add(artifact);
+            addWithCheck(artifact, compileDependencies);
+            continue;
+        }
+    }
+
+    /** parse the Managed Dependencies from the provided item
+     * @param item  what to parse
+     */
+    private void parseManagedDependencies(final Element item) {
+        final List<Element> dependencies = ElementSupport.getChildElementsByTagName(item, "dependency");
+        for (Element dependency : dependencies) {
+            final PomArtifact artifact = new PomArtifact(dependency);
+            final List<Element> types = ElementSupport.getChildElementsByTagName(dependency, "type");
+            if (!types.isEmpty()) {
+                final String type = StringSupport.trimOrNull(types.get(0).getTextContent());
+                if ("pom".equals(type)) {
+                    addWithCheck(artifact, bomDependencies);
+                    continue;
+                } else if (!"jar".equals(type)) {
+                    // not for us
+                    continue;
+                }
+            }
+            addWithCheck(artifact, managedDependencies);
+        }
+    }
+
+    /** Add the artifact to the map, accumulating duplicates.
+     * @param artifact what to add
+     * @param map wghere to add it
+     */
+    private void addWithCheck(final PomArtifact artifact, final Map<String, PomArtifact> map) {
+        final PomArtifact old = map.put(artifact.getMapKey(),artifact);
+        if (old != null) {
+            duplicates.add(new Pair<>(old, artifact));
         }
     }
 
@@ -206,7 +278,8 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
         
         for (final Element child : ElementSupport.getChildElements(item)) {
             final String name = child.getLocalName();
-            final String value = child.getTextContent();
+            final String value = getElementContent(child);
+            
             properties.setProperty(name, value);
         }
     }
@@ -217,33 +290,40 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
     private void parseParent(Element item) {
         parent = new PomArtifact(item);
     }
-    
+
     /** Returns the Compile Dependencies.
      * @return Returns the Compile Dependencies.
      */
-    public List<PomArtifact> getCompileDependencies() {
-        return compileDependencies;
+    @Nonnull public Collection<PomArtifact> getCompileDependencies() {
+        return compileDependencies.values();
     }
 
-    /** Returns the Bom Dependencies.
-     * @return Returns the Bom Dependencies.
-     */
-    public List<PomArtifact> getBomDependencies() {
-        return bomDependencies;
-    }
-    
     /** Returns the Runtime Dependencies.
      * @return Returns the Runtime Dependencies.
      */
-    public List<PomArtifact> getRuntimeDependencies() {
-        return runtimeDependencies;
+    @Nonnull public Collection<PomArtifact> getRuntimeDependencies() {
+        return runtimeDependencies.values();
     }
-    
+
     /**  Returns the Managed Dependencies.
      * @return Returns the Managed Dependencies.
      */
-    public List<PomArtifact> getManagedDependencies() {
-        return myManagedDependencies;
+    @Nonnull public Map<String, PomArtifact> getManagedDependencies() {
+        return managedDependencies;
+    }
+
+    /** Get artifacts that were duplicated by this build
+     * @return Returns the duplicates.
+     */
+    @Nonnull public List<Pair<PomArtifact, PomArtifact>> getDuplicates() {
+        return duplicates;
+    }
+
+    /** returns any sub modules created by this module.
+     * @return Returns the generated.
+     */
+    @Nonnull public Set<PomArtifact> getGeneratedArtifacts() {
+        return generated;
     }
 
     /** Return our artifactInformation.
@@ -335,7 +415,7 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
             } else if (parentArtifact != null) {
                 version = parentArtifact.getVersion();
             } else {
-                final PomArtifact inherited = inputManagedDependencies.get(groupId+"+"+artifactId);
+                final PomArtifact inherited = managedDependencies.get(groupId+"+"+artifactId);
                 if (inherited != null) {
                     version = inherited.getVersion();
                 } else {
@@ -386,6 +466,13 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
             return sourcePomInfo;
         }
         
+        /** Get the key we use in out maps.
+         * @return the key - derives from groupId and EntityId 
+         */
+        public String getMapKey() {
+            return getGroupId()+"+"+getArtifactId();
+        }
+        
         /**
          * @return Returns the exclusions.
          */
@@ -413,6 +500,11 @@ public class ParsedPom extends OpenSAMLInitBaseTestCase{
         public int hashCode() {
             return Objects.hash(artifactId, groupId, version);
         }
+        
+        /** {@inheritDoc} */
+        public String toString() {
+            return artifactId + "-" + version;
+        }
 
         /** return the same artifact but with an amended version.
          * @param ver the version
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/dependencies/PomLoader.java b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/PomLoader.java
new file mode 100644
index 000000000..a539cb71d
--- /dev/null
+++ b/idp-installer/src/test/java/net/shibboleth/idp/dependencies/PomLoader.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.dependencies;
+
+import java.nio.file.Path;
+
+import net.shibboleth.idp.dependencies.ParsedPom.PomArtifact;
+
+/**
+ * Abstraction of a way to get hold of a pom.
+ */
+public interface PomLoader {
+
+    /** tell Something to download the artifact and returns it's path.
+     * @param artifact what to look for
+     * @return the pom as a {@link Path}
+     * @throws Exception 
+     */
+    Path downloadPom(PomArtifact artifact) throws Exception;
+
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list