diff --git a/dependencyanalyser/.gitignore b/dependencyanalyser/.gitignore new file mode 100644 index 0000000..029cbfe --- /dev/null +++ b/dependencyanalyser/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.factorypath +/.project diff --git a/dependencyanalyser/.settings/.gitignore b/dependencyanalyser/.settings/.gitignore new file mode 100644 index 0000000..d726907 --- /dev/null +++ b/dependencyanalyser/.settings/.gitignore @@ -0,0 +1,3 @@ +/org.eclipse.jdt.apt.core.prefs +/org.eclipse.jdt.core.prefs +/org.eclipse.m2e.core.prefs diff --git a/dependencyanalyser/README.md b/dependencyanalyser/README.md new file mode 100644 index 0000000..2569a5f --- /dev/null +++ b/dependencyanalyser/README.md @@ -0,0 +1,128 @@ +# Dependency Scanner + +This program will scan the dependency sources it is given and build a combined dependency tree combining the separate dependency trees for the inputs. This allows the detection of conflicting dependencies. While maven (and other build tools) can of course determine conflicting dependencies in the jar files they manage (and copy into the resulting targets) this only applies at compile time, not run time, where a jar file is provided by the end user (or the end user replaces a jar file in the inputs). The goal of this program is to enable the provision of a set of the top level input jar files and the dependency trees for each will be checked for conflicting versions. For example a developer may build an application against what will ultimately be a user supplied library (the maven `provided` scope). At the compile stage the application will be compiled against the version in that build, however a user may subsequently use a different version of that library (and the jar files associated with it) If the original compiled version had a different version of the library which was replaced (or the provided version was replaced by the developer mandated version) then conflicts may occur. + +## Usage +The class `com.oracle.timg.demo.dependencyanalyser.DependencyScanner` is the main class. is supports the following arguments: + + `-d`/`--directory` followed by working directory location - required when doing something that generates an intermediate file, for example extracting a pom.xml or generating a graph-xml file. In practice (with the current loaders) this basically means in all situation. Defaults to the current directory and can be absolute or relative, it must exist and of course you must be able to read and write it. + + `-g`/`--groupid` followed by groupid - Optional and used for setting the groupid at the root of the combined dependency tree, defaults to `my.company` if not set. Recommended if listing jar files or similar so you can determine what the actual tree root will be in the output + + `-a`/`--artifactid` followed by artifactid - Optional and used for setting the artifact at the root of the combined dependency tree, defaults to `myartifact` if not set. Recommended if listing jar files or similar so you can determine what the actual tree root will be in the output + + `-v`/`--version` followed by version string - Optional and used for setting the version at the root of the combined dependency tree, defaults to `0.0.0` if not set. Recommended if listing jar files or similar so you can determine what the actual tree root will be in the output + + `-m`/`--maven-path` followed by path - Required for all sources that are maven based (so pom.xmnl files of jar files with a ponm.xml contents. Specified the location of the mvn executabler. Note that this **MUST** be the full absolute path, there is no default as this is system dependent. + + `-r`/`--resolve-dependencies` - If set will call any pre-resolving task needed before generating dependency data, used for example to ensure that the local mavan repo has ll of the dependencies downloaded. Defaults to false. + + `-i`/`--retain-intermediates` - If set will retain the intermediate files (e.g. extracted pom.xml) used for the processing stages, this can be useful for debugging purposes. Defaults to false. + + `-V`/`--Verbose` - outputs info re the sub processes that are run (e.g. command lines being used, output from the sub processes) + + + The remaining arguments are treated as input sources. Currently the following are supported. + + Files with the suffix `.mvn-graphml.xml` These are assumed to contain a GraphML "dump" of the dependencies in the format that Maven outputs. The file will be directly loaded and to locate the root of the dependency tree all loaded jars are scanned to find a jar version which does not depend on any other source. This resulting tree will be added to the combined dependencies tree. The root of this source will be created as a sub node under the combined root tree and will have it's scope set to 'ROOT', + + Files with the name `pom.xml` - These files will be passed to maven to create a maven dependency graqph file (with the suffix `.mvn-graphml.xml`) which will then be loaded and added to the combined dependencies tree using the process above if the `-r` flag is set then maven will be asked to do a dependency resolve stage before processing. The .mvn-graplml.xml file will be generated using a temporary name based on thye grupid, artifactid and version located in the ponm.xml file and will be written to the location specified by the `-d` flag, if the `-i` flag is set this temporary file will be retained, otherwise it will be deleted when the jvm exits. If the `-V` flag is set the the command(s) used to run maven and any maven output will be displayed. + + Files with the suffix `.jar` are examined to see if they contain a `pom.xml` file and optionally a `pom.properties` file. These are expected to be under the `META-INF/maven//` "directory" in the jar file (If Maven is packaging the jar file it will copy the files there automatically, Gradle seem to also generate at least a `pom.xml` file which is places there as well). If present the `pom.properties` file will be used to get the groupid, artifactid and version, if `pom.properties` is not present these will be extracted from the `pom.xml` entri. The `META-INF/maven///pom.xml` entry in the jar file will then be extracted and copied into a temporaty file and then the process above is done as with a "normal" pom.xml file. + +## Outputs + + The DependencyScanner class is provided as an example, it loads each of the source arguments in turn and then generates the output. There are a number of utility medhods in the JarTree class that can be used to locate jar file versions based on different criteria and also to dump the dependeny tree. + + Count of the number of Jar files where there are two or move versions in the combined dependency tree + + Information on each oif the jar files with multiple versions including the jar file versions that depend in this version, any jar file versions that they depend on and also details of the original source jar file version to help identify wherte conflicting versions originate from (this maps to the input sources). + + It will also list the number of jar file versions that have no dependencies (i.e. "leaf" jar file versions) and also the bymber of jar file versions. Depending on the other flags and arguments other output may of course be provided. + + Below is the core output from test code. This is deliberately using different versions of Lombok, please note that the number of jar file versions with nothign depending should always be one (this being the "root / project" dependency. + + ```text + May 20, 2024 2:42:23 PM com.oracle.timg.demo.dependencyanalyser.DependencyScanner main +INFO: Count of combined Jar files with two or more versions +3 +May 20, 2024 2:42:23 PM com.oracle.timg.demo.dependencyanalyser.DependencyScanner main +INFO: Details of jar files with multiple versions +org.projectlombok:lombok + 1.18.30 refs = 1 + Depends on + Depended on by + com.oracle.labs.helidon.fileio:filewriter:1.0.0 (PROVIDED) + In source + com.oracle.labs.helidon.fileio:filewriter:1.0.0 from origional source testdata/filewriter.mvn-graphml.xml + + 1.18.32 refs = 2 + Depends on + Depended on by + com.oracle.timg.demo:dependencyanalyser:0.0.1-SNAPSHOT (PROVIDED) + com.oracle.labs.helidon.fileio:filereader:1.0.0 (PROVIDED) + In source + com.oracle.timg.demo:dependencyanalyser:0.0.1-SNAPSHOT from origional source testdata/pom.xml + com.oracle.labs.helidon.fileio:filereader:1.0.0 from origional source testdata/filereader.mvn-graphml.xml + +org.apiguardian:apiguardian-api + 1.0.0 refs = 1 + Depends on + Depended on by + com.oracle.labs.helidon.fileio:filereader:1.0.0 (COMPILE) + In source + com.oracle.labs.helidon.fileio:filereader:1.0.0 from origional source testdata/filereader.mvn-graphml.xml + + 1.1.2 refs = 1 + Depends on + Depended on by + org.junit.jupiter:junit-jupiter-api:5.9.3 (TEST) + In source + com.oracle.labs.helidon.fileio:filewriter:1.0.0 from origional source testdata/filewriter.mvn-graphml.xml + +jakarta.activation:jakarta.activation-api + 1.2.2 refs = 1 + Depends on + Depended on by + jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 (COMPILE) + In source + com.oracle.timg.demo:dependencyanalyser:0.0.1-SNAPSHOT from origional source testdata/pom.xml + + 2.1.1 refs = 2 + Depends on + Depended on by + com.oracle.labs.helidon.fileio:filewriter:1.0.0 (COMPILE) + com.oracle.labs.helidon.fileio:filereader:1.0.0 (COMPILE) + In source + com.oracle.labs.helidon.fileio:filewriter:1.0.0 from origional source testdata/filewriter.mvn-graphml.xml + + +May 20, 2024 2:42:23 PM com.oracle.timg.demo.dependencyanalyser.DependencyScanner main +INFO: Combined Jar versions with no dependencies 87 +May 20, 2024 2:42:23 PM com.oracle.timg.demo.dependencyanalyser.DependencyScanner main +INFO: Combined Jar versions with no depended on 1 +``` + + + +## Known limitations + +This program uses Mavan to build the per project tree, the program then loads the maven dependency output and combines it with all other supplied outputs. Of course this means that the mvn command needs to be available. it also means that it is subject to mavens restrictions and limitations. Known factors that may cause a problem are : + +1. You need to have resolved all the dependencies in any pom.xml (or jar file containing it) to do that the program has the option of running a maven resolve stage (set the `-r` flag), this can take a while and you will need a network connection and enough space on the machine you are using to download the dependencies. + +2. Maven supports the operation of relative parent pom.xml, for some projects where the jar file (or pom.xml) is not in the local maven repository this may be a problem as the parent pom may not be in the right place in the directory tree, in some situations where there happens to be a pom.xml (not not the expected one) in the location specified by the relativePath this will result in maven loading the incorrect parent pom. + +3. Of course if mvn output changes (or the mvn command and flags change) then this will be a problem. + +## Extending the code + +Is is architecturally possible to add additional sources of dependency information. The new loader needs to implement the SourceLoader interface, the GetSourceLoader class needs to be updated to recognize (by whatever means you like) the new source type and return an instance of the appropriate loader. + +The loadDependencied method needs to return a new Jar Tree which will then be combined with all of the others that have been built. The new Jar Tree has the following criteria. + +The getRoot method must return an IdenfitiedJarFileVersion which is the root of the new dependency structure, this must not have anything depending on it. + +This must be a tree, no loops are allowed (this is really a limitation of the output mechanisms) + +Every IdenfitiedJarFileVersion in the tree must contain the tree being built in the sourceProjecxtrs set (this will be combined with the other sources later and used in the output to trace the source of multiple dependencies diff --git a/dependencyanalyser/pom.xml b/dependencyanalyser/pom.xml new file mode 100644 index 0000000..47def5e --- /dev/null +++ b/dependencyanalyser/pom.xml @@ -0,0 +1,88 @@ + + + + 4.0.0 + com.oracle.timg.demo + dependencyanalyser + 0.0.1-SNAPSHOT + dependencyanalyser + analysies mvn output file looking for conflicting dependencies + + 1.18.32 + 2.37 + + + + + + + + + + + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + + + org.glassfish.jaxb + jaxb-runtime + runtime + 2.3.3 + + + + org.projectlombok + lombok + ${version.lombok} + provided + + + com.kazurayam + subprocessj + 0.3.7 + + + args4j + args4j + ${version.args4j} + + + \ No newline at end of file diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/Dependency.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/Dependency.java new file mode 100644 index 0000000..a3f02f2 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/Dependency.java @@ -0,0 +1,61 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode + +public class Dependency implements Comparable { + @EqualsAndHashCode.Exclude + private final IdentifiedJarVersion source; + @EqualsAndHashCode.Include + private final IdentifiedJarVersion target; + @EqualsAndHashCode.Include + private final ScopeType scope; + + @Override + public int compareTo(Dependency dependency) { + return (target.toString() + scope).compareTo(dependency.target.toString() + dependency.scope); + } + + public Dependency dupeCore(IdentifiedJarVersion newSource, IdentifiedJarVersion newTarget) { + return new Dependency(newSource, newTarget, this.scope); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyLoadTester.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyLoadTester.java new file mode 100644 index 0000000..fdf6694 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyLoadTester.java @@ -0,0 +1,102 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.io.File; +import java.util.stream.Collectors; + +import com.oracle.timg.demo.dependencyanalyser.importers.MavenGraphLoader; + +import lombok.extern.java.Log; + +@Log +public class DependencyLoadTester { + + public final static void main(String args[]) throws Exception { +// JarTree jarTreeReader = new JarTree("com.oracle.labs.helidon.fileio", "filereader", "1.0.0", "jar", +// ScopeType.ROOT); + MavenGraphLoader loader = new MavenGraphLoader(new OptionsData()); + JarTree jarTreeReader = loader.loadDependencyTree(new File(args[0])); +// log.info("JarFiles list is :\n" + jarTreeReader.listJarFiles()); +// log.info("JarFiles details list is :\n" + jarTreeReader.listJarFileDetails()); + log.info("Jar files with no versions " + jarTreeReader.getJarFilesWithNoVersions().size()); + log.info("Jar files with two or more versions " + + jarTreeReader.getJarFilesWithMoreThanSpecifiedVersions(1).size()); + log.info("Jar versions with no dependencies " + jarTreeReader.getJarVersionsWithNoDependencies().size()); + log.info("Jar versions with no depended on " + jarTreeReader.getJarVersionsWithNoDependOn().size()); + log.info("Root jar version details \n" + jarTreeReader.getRoot().getParent().toVersionDetails("")); + JarTreeCombiner combiner = new JarTreeCombiner("com.oracle.timg", "filehandling", "1.0.0"); +// log.warning( +// "Combiner root pre combine is\n" + combiner.getProjectTop().getRoot().getParent().toVersionDetails("")); +// log.warning("combined jar versions pre combine " + combiner.getProjectJarVersions().keySet()); +// // bring in the tree we just loaded + combiner.addJarTree(jarTreeReader); +// log.warning("Combiner root post combine is\n" +// + combiner.getProjectTop().getRoot().getParent().toVersionDetails("")); +// log.warning("combined jar versions post combine " + combiner.getProjectJarVersions().keySet()); +// // get the first dependency in ther first version, then dump the target + JarTree combinedTree = combiner.getProjectTop(); +// IdentifiedJarVersion firstTarget = new ArrayList<>(combinedTree.getRoot().getDependsOn()).get(0).getTarget(); +// log.info("combined first dependency (should be file reader)\n" + firstTarget.getParent().toVersionDetails("")); +//// log.info("Combined JarFiles list is :\n" + combinedTree.listJarFiles()); +//// log.info("Combined JarFiles details list is :\n" + combinedTree.listJarFileDetails()); +// log.info("Combined Jar files with no versions " + combinedTree.getJarFilesWithNoVersions().size()); +// log.info("Combined Jar files with two or more versions " +// + combinedTree.getJarFilesWithMoreThanSpecifiedVersions(1).size()); +// log.info( +// "Combined Jar versions with no dependencies " + combinedTree.getJarVersionsWithNoDependencies().size()); +// log.info("Combined Jar versions with no depended on " + combinedTree.getJarVersionsWithNoDependOn().size()); +//// log.info("Combined Root jar version details \n" + combinedTree.getRoot().getParent().toVersionDetails("")); +// log.info("Scanning second tree"); +// + JarTree jarTreeWriter = loader.loadDependencyTree(new File(args[1])); + +// log.warning("doing second combine"); + combiner.addJarTree(jarTreeWriter); +//// + log.warning("Combiner root post second combine is\n" + + combiner.getProjectTop().getRoot().getParent().toVersionDetails("")); + log.warning("combined jar versions post second combine " + combiner.getProjectJarVersions().keySet()); + log.info("Combined final jar tree is :\n" + combinedTree.dumpTree("")); + log.info("Combined final keys \n" + combinedTree.keySet()); + log.info("Project root final jar version dependencies " + combinedTree.getRoot().getDependsOn()); + log.info("Combined Jar files with two or more versions " + + combinedTree.getJarFilesWithMoreThanSpecifiedVersions(1).stream() + .map(jarversion -> jarversion.toVersionDetails("", true)).collect(Collectors.joining("\n"))); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyProcessorException.java new file mode 100644 index 0000000..dcaad3a --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyProcessorException.java @@ -0,0 +1,63 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +public class DependencyProcessorException extends Exception { + + private static final long serialVersionUID = 529077741205885816L; + + public DependencyProcessorException() { + super(); + } + + public DependencyProcessorException(String arg0) { + super(arg0); + } + + public DependencyProcessorException(Throwable arg0) { + super(arg0); + } + + public DependencyProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public DependencyProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyScanner.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyScanner.java new file mode 100644 index 0000000..669ca35 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/DependencyScanner.java @@ -0,0 +1,117 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.io.File; +import java.util.Set; +import java.util.stream.Collectors; + +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.spi.Messages; + +import com.oracle.timg.demo.dependencyanalyser.importers.GetSourceLoader; +import com.oracle.timg.demo.dependencyanalyser.importers.SourceLoader; + +import lombok.extern.java.Log; + +@Log +public class DependencyScanner { + + public final static void main(String args[]) throws Exception { + // process the args + OptionsData options = new OptionsData(); + CmdLineParser parser = new CmdLineParser(options); + try { + // parse the arguments. + parser.parseArgument(args); + if (options.sources.isEmpty()) { + throw new CmdLineException(parser, Messages.DEFAULT_META_REST_OF_ARGUMENTS_HANDLER, + "No sources provided"); + } + } catch (CmdLineException e) { + // if there's a problem in the command line, + // you'll get this exception. this will report + // an error message. + System.err.println(e.getMessage()); + // print the list of available options + parser.printUsage(System.err); + System.err.println(); + return; + } + log.fine("Processed options are :\n" + options); + // place to put the results + JarTreeCombiner combiner = new JarTreeCombiner(options.getGroupid(), options.getArtifactid(), + options.getVersion()); + // let's process the args + options.getSources().stream().forEach(source -> processSource(options, source, combiner)); + + log.fine("Combiner root post combine is\n" + + combiner.getProjectTop().getRoot().getParent().toVersionDetails("")); + JarTree combinedTree = combiner.getProjectTop(); + Set multiVersionJarFiles = combinedTree.getJarFilesWithMoreThanSpecifiedVersions(1); + log.info("Count of combined Jar files with two or more versions\n" + multiVersionJarFiles.size()); + log.info("Details of jar files with multiple versions\n" + multiVersionJarFiles.stream() + .map(jarFile -> jarFile.toVersionDetails("", true)).collect(Collectors.joining("\n", "", "\n"))); + log.info( + "Combined Jar versions with no dependencies " + combinedTree.getJarVersionsWithNoDependencies().size()); + log.info("Combined Jar versions with no depended on " + combinedTree.getJarVersionsWithNoDependOn().size()); + } + + private static void processSource(OptionsData options, File source, JarTreeCombiner combiner) { + log.info("Loading source " + source.getPath()); + SourceLoader loader; + try { + loader = GetSourceLoader.getSourceLoader(options, source); + } catch (DependencyProcessorException e) { + log.warning( + "SourceLoader cannot process source " + source.getPath() + " due to " + e.getLocalizedMessage()); + return; + } + JarTree loadedJarTree; + try { + loadedJarTree = loader.loadDependencyTree(source); + } catch (DependencyProcessorException e) { + log.warning("SourceLoader cannot load source " + source.getPath() + " due to " + e.getLocalizedMessage()); + return; + } + log.info("Combining source " + source.getPath() + " with " + combiner.getProjectJarVersions().size() + + " jar versions already loaded"); + // now add it to the tree wew're building up + combiner.addJarTree(loadedJarTree); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarFile.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarFile.java new file mode 100644 index 0000000..95228b0 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarFile.java @@ -0,0 +1,108 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.util.TreeMap; +import java.util.stream.Collectors; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class IdentifiedJarFile extends TreeMap implements Comparable { + private static final long serialVersionUID = 7088951357215826846L; + @EqualsAndHashCode.Include + @NonNull + private final String groupId; + @EqualsAndHashCode.Include + @NonNull + private final String artifactId; + @EqualsAndHashCode.Exclude + private boolean fromSource = true; + @EqualsAndHashCode.Exclude + private int refCount = 0; + + public IdentifiedJarFile duplicateCore() { + IdentifiedJarFile newJarFile = new IdentifiedJarFile(this.groupId, this.artifactId); + newJarFile.setFromSource(false); + return newJarFile; + } + + public int incrRefCount() { + refCount++; + return refCount; + } + + public int decrCount() { + refCount--; + return refCount; + } + + @Override + public String toString() { + return processString(groupId, artifactId); + } + + public static String processString(String groupId, String artifactId) { + return groupId + ":" + artifactId; + } + + public String toVersionList(String indentString) { + return indentString + toString() + "\n" + this.values().stream() + .map(version -> indentString + " " + version.getVersion()).collect(Collectors.joining("\n")); + } + + public String toVersionDetails(String indentString) { + return toVersionDetails(indentString, false); + } + + public String toVersionDetails(String indentString, boolean includeSources) { + return indentString + toString() + "\n" + + this.values().stream().map(version -> version.toFullString(indentString + " ", includeSources)) + .collect(Collectors.joining("\n")); + } + + @Override + public int compareTo(IdentifiedJarFile other) { + return this.toString().compareTo(other.toString()); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarVersion.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarVersion.java new file mode 100644 index 0000000..e105d4e --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/IdentifiedJarVersion.java @@ -0,0 +1,182 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; + +@Data +public class IdentifiedJarVersion implements Comparable { + @EqualsAndHashCode.Include + @NonNull + private final String version; + @EqualsAndHashCode.Exclude + @NonNull + private final IdentifiedJarFile parent; + @EqualsAndHashCode.Exclude + @NonNull + private final String type; + @EqualsAndHashCode.Exclude + @NonNull + private final ScopeType scope; + // what depends on us - assumes that a dependency of say + // com.fred.test.program:1.2.1 is always the same actual target of a dependency + @EqualsAndHashCode.Exclude + private final Set dependsOn = new TreeSet<>(); + // the things that depend on us (for reporting on conflict trees) + @EqualsAndHashCode.Exclude + private final LinkedList dependsOnThis = new LinkedList<>(); + // used to track the source projects this jar version came from + @EqualsAndHashCode.Exclude + private final Set sourceProjects = new TreeSet<>(); + @EqualsAndHashCode.Exclude + private int refCount = 0; + @EqualsAndHashCode.Exclude + private boolean fromSource = true; + + public IdentifiedJarVersion() { + this.version = ""; + this.parent = null; + this.type = ""; + this.scope = ScopeType.ERROR; + + } + + public IdentifiedJarVersion(@NonNull String version, @NonNull IdentifiedJarFile parent, @NonNull String type, + @NonNull ScopeType scope) { + this(version, parent, type, scope, null); + } + + public IdentifiedJarVersion(String version, IdentifiedJarFile parent, String type, ScopeType scope, + JarTree sourceProject) { + this.version = version; + this.parent = parent; + this.type = type; + this.scope = scope; + if (sourceProject != null) { + this.sourceProjects.add(sourceProject); + } + } + + public IdentifiedJarVersion duplicateCore(@NonNull IdentifiedJarFile newParent) { + IdentifiedJarVersion newJarVersion = new IdentifiedJarVersion(version, newParent, type, scope); + newJarVersion.addSourceProjects(sourceProjects); + // duplicates are by definition not from the core + newJarVersion.setFromSource(false); + return newJarVersion; + } + + public boolean equals(@NonNull IdentifiedJarVersion other) { + return version.equals(other.version); + } + + public int hashCode() { + return version.hashCode(); + } + + public int incrRefCount() { + refCount++; + return refCount; + } + + public int decrCount() { + refCount--; + return refCount; + } + + public void addSourceProjects(@NonNull Collection sourceProjectToAdd) { + this.sourceProjects.addAll(sourceProjectToAdd); + } + + @Override + public String toString() { + return processString(parent.getGroupId(), parent.getArtifactId(), version); + } + + public String toFullerString(String indentString) { + return indentString + processString(parent.getGroupId(), parent.getArtifactId(), version) + "Has " + + dependsOn.size() + " Dependencies and " + dependsOnThis.size() + " that depend on it"; + } + + public static String processString(String groupId, String artifactId, String version) { + return groupId + ":" + artifactId + ":" + version; + } + + public String toFullString(String indentString) { + return toFullString(indentString, false); + } + + public String toFullString(String indentString, boolean includeSources) { + String vsn = indentString + version + " refs = " + getRefCount() + "\n"; + String dependsOnString = indentString + " " + "Depends on\n"; + if (dependsOn.size() > 0) { + dependsOnString += dependsOn.stream() + .map(dependency -> dependency.getTarget().toString() + " (" + dependency.getScope() + ")") + .collect(Collectors.joining("\n" + indentString + " ", indentString + " ", "\n")); + } + String dependsOnThisString = indentString + " " + "Depended on by\n"; + if (dependsOnString.length() > 0) { + dependsOnThisString += dependsOnThis.stream() + .map(depender -> depender.getSource().toString() + " (" + depender.getScope() + ")") + .collect(Collectors.joining("\n" + indentString + " ", indentString + " ", "\n")); + } + String resp = vsn + dependsOnString + dependsOnThisString; + if (includeSources) { + String sources = indentString + " " + "In source\n"; + sources += sourceProjects.stream().map(sourceTree -> sourceTree.getRootDescription()) + .collect(Collectors.joining("\n" + indentString + " ", indentString + " ", "\n")); + resp = resp += sources; + } + return resp; + } + + @Override + public int compareTo(IdentifiedJarVersion target) { + return this.version.compareTo(target.version); + } + + public void addSourceProject(@NonNull JarTree sourceProject) { + this.sourceProjects.add(sourceProject); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTree.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTree.java new file mode 100644 index 0000000..80e655d --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTree.java @@ -0,0 +1,165 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; + +@Data +@EqualsAndHashCode(callSuper = false) +@RequiredArgsConstructor +public class JarTree extends TreeMap implements Comparable { + private static final long serialVersionUID = -1545900389748317346L; + private IdentifiedJarVersion root = new IdentifiedJarVersion(); + private final File origionalSourceFile; + + public JarTree(String groupId, String artifactId, String jarFileVersionString, String jarFileType, + ScopeType jarScope) { + this(groupId, artifactId, jarFileVersionString, jarFileType, jarScope, null); + } + + public JarTree(String groupId, String artifactId, String jarFileVersionString, String jarFileType, + ScopeType jarScope, File origionalSourceFile) { + this.origionalSourceFile = origionalSourceFile; + IdentifiedJarFile identifiedJarFile = new IdentifiedJarFile(groupId, artifactId); + IdentifiedJarVersion identifiedJarVersion = new IdentifiedJarVersion(jarFileVersionString.trim(), + identifiedJarFile, jarFileType, jarScope); + identifiedJarFile.put(jarFileVersionString.trim(), identifiedJarVersion); + this.root = identifiedJarVersion; + this.put(IdentifiedJarFile.processString(groupId, artifactId).trim(), identifiedJarFile); + identifiedJarVersion.addSourceProject(this); + } + + public String dumpTree(IdentifiedJarVersion jarVersionCurrent, String indent, ScopeType scopeType, int depth) { + // do a depth first dump with indentation + String resp = indent; + String subIndent = indent + "|---"; + // try to get the dependency link scope types + List dependentScopes; + if (jarVersionCurrent.getDependsOnThis().size() == 0) { + dependentScopes = new ArrayList<>(1); + dependentScopes.add(ScopeType.ROOT); + } else { + dependentScopes = jarVersionCurrent.getDependsOnThis().stream().map(dependecyOn -> dependecyOn.getScope()) + .collect(Collectors.toList()); + } + resp += jarVersionCurrent.toString() + " (" + dependentScopes + " refs = " + jarVersionCurrent.getRefCount() + + ")\n"; + if (depth == 0) { + return resp + "\n" + "Reached specified depth\n"; + } + int newDepth; + if (depth > 0) { + newDepth = depth - 1; + } else { + newDepth = depth; + } + // process the dependencies + String dependencyString = jarVersionCurrent.getDependsOn().stream() + .map(dependency -> dumpTree(dependency.getTarget(), subIndent, dependency.getScope(), newDepth)) + .collect(Collectors.joining()); + return resp + dependencyString; + + } + + public String dumpTree() { + return this.dumpTree("", -1); + } + + public String dumpTree(String indent) { + return this.dumpTree(indent, -1); + } + + public String dumpTree(String indent, int depth) { + return this.dumpTree(root, indent, root.getScope(), depth); + } + + @Override + public int compareTo(JarTree other) { + return this.root.compareTo(other.root); + } + + public String listJarFiles() { + return this.entrySet().stream().map(entry -> entry.getValue().toVersionList("")) + .collect(Collectors.joining("\n")); + } + + public String listJarFileDetails() { + return listJarFileDetails(false); + } + + public String listJarFileDetails(boolean includeSources) { + return this.entrySet().stream().map(entry -> entry.getValue().toVersionDetails("", includeSources)) + .collect(Collectors.joining("\n")); + } + + public Set getJarFilesWithNoVersions() { + return this.values().stream().filter(jarFile -> jarFile.isEmpty()).collect(Collectors.toSet()); + } + + public Set getJarFilesWithMoreThanSpecifiedVersions(int maxVersionCount) { + return this.values().stream().filter(jarFile -> jarFile.size() > maxVersionCount).collect(Collectors.toSet()); + } + + public Set getJarVersionsWithNoDependencies() { + return this.values().stream().flatMap(jarFile -> jarFile.values().stream()) + .filter(version -> version.getDependsOn().size() == 0).collect(Collectors.toSet()); + } + + public Set getJarVersionsWithNoDependOn() { + return this.values().stream().flatMap(jarFile -> jarFile.values().stream()) + .filter(version -> version.getDependsOnThis().size() == 0).collect(Collectors.toSet()); + } + + public String getRootDescription() { + String resp = this.getRoot().toString(); + if (origionalSourceFile == null) { + resp += " no origional source file available"; + } else { + resp += " from origional source " + origionalSourceFile.getPath(); + } + return resp; + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTreeCombiner.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTreeCombiner.java new file mode 100644 index 0000000..731efa7 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/JarTreeCombiner.java @@ -0,0 +1,186 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.util.Map; +import java.util.TreeMap; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.java.Log; + +@Log +@Data +public class JarTreeCombiner { + public final static String PROJECT_FILE_TYPE = "project"; + public final static ScopeType PROJECT_SCOPE_TYPE = ScopeType.PROJECT; + private JarTree projectTop; + @EqualsAndHashCode.Exclude + private Map projectJarVersions = new TreeMap<>(); + + public JarTreeCombiner(String groupId, String artifactId, String projectVersionString) { + this.projectTop = new JarTree(groupId, artifactId, projectVersionString, PROJECT_FILE_TYPE, PROJECT_SCOPE_TYPE); + projectTop.getRoot().getParent().setFromSource(false); + projectTop.getRoot().setFromSource(false); + // get the "root" project jar version we just created and stash it for later + // access + projectJarVersions.put(projectTop.getRoot().toString().trim(), projectTop.getRoot()); + + } + + public void addJarTree(JarTree jarTree) { + // force up the root connection to our project + IdentifiedJarVersion incomingRootJarVersion = jarTree.getRoot(); + // if the jar file is already processed then no need to setup the new one + String incommingRoofJarFileName = incomingRootJarVersion.getParent().toString(); + IdentifiedJarFile newRootJarFile = projectTop.get(incommingRoofJarFileName.trim()); + if (newRootJarFile == null) { + log.finer("Cannot locate incomming root jar file " + incommingRoofJarFileName + ", creating"); + newRootJarFile = incomingRootJarVersion.getParent().duplicateCore(); + // stash it in the new jar tree + projectTop.put(newRootJarFile.toString().trim(), newRootJarFile); + // in this case the jar file will (should) also be in the incoming tree, so + // reduce the ref count + // to reflect we've set it up already + newRootJarFile.decrCount(); + } else { + log.finer("Located an existing jar file for the project root of " + incommingRoofJarFileName); + } + // sort out the jar version + String incomingRootJarVersionName = incomingRootJarVersion.getVersion(); + IdentifiedJarVersion newRootJarVersion = newRootJarFile.get(incomingRootJarVersionName.trim()); + if (newRootJarVersion == null) { + log.finer("Cannot locate incomming root jar version " + incomingRootJarVersionName + ", creating"); + newRootJarVersion = incomingRootJarVersion.duplicateCore(newRootJarFile); + // add the new version info to the new jar file + newRootJarFile.put(incomingRootJarVersionName.trim(), newRootJarVersion); + // put the new jar version in the main stash so we can get it later when setting + // up the dependencies + projectJarVersions.put(newRootJarVersion.toString().trim(), newRootJarVersion); + } else { + log.finer("Located incomming root jar version " + incomingRootJarVersionName + ", reusing"); + } + newRootJarVersion.incrRefCount(); + // setup the dependency, this will link the project root to the incoming tree + // root duplicate + Dependency dependency = new Dependency(projectTop.getRoot(), newRootJarVersion, PROJECT_SCOPE_TYPE); + // add the dependencies in place + projectTop.getRoot().getDependsOn().add(dependency); + newRootJarVersion.getDependsOnThis().add(dependency); + // copy over all of the jar files and version details + addAllJarFilesAndVersions(jarTree); + // now we have everything we need for the dependencies + addAllDependencies(jarTree); + } + + private void addAllJarFilesAndVersions(JarTree incommingJarTree) { + // for every incoming jar file get the jar file from the main tree, creating if + // needed + incommingJarTree.entrySet().stream().forEach(jarFileEntry -> { + String jarName = jarFileEntry.getKey(); + IdentifiedJarFile incommingJarFile = jarFileEntry.getValue(); + IdentifiedJarFile mainJarFile = projectTop.get(jarName.trim()); + // we don't have this yet create a new one + if (mainJarFile == null) { + mainJarFile = incommingJarFile.duplicateCore(); + projectTop.put(jarName.trim(), mainJarFile); + } + mainJarFile.incrRefCount(); + // for the next stream to work the jar file must be final so + IdentifiedJarFile finalMainJarFile = mainJarFile; + // for every version of that jar file add it to the main tree version (the jar + // file itself must exist as we have just created it if needed) + incommingJarFile.entrySet().stream().forEach(jarVersionEntry -> { + String versionName = jarVersionEntry.getKey(); + IdentifiedJarVersion incommingJarVersion = jarVersionEntry.getValue(); + IdentifiedJarVersion mainJarVersion = finalMainJarFile.get(versionName.trim()); + // if the version does not exist in the main jar version then create and add it + // then add the original jar versions source projects (the source JarTree) to + // the + // main trees version source projects (let's us identify the source of a + // conflict) + if (mainJarVersion == null) { + // this will copy over the original source project + mainJarVersion = incommingJarVersion.duplicateCore(finalMainJarFile); + finalMainJarFile.put(versionName.trim(), mainJarVersion); + // stash a direct link to the version to speed up access later + projectJarVersions.put(mainJarVersion.toString().trim(), mainJarVersion); + } else { + // the version exists, but we need to add the source projects to the existing + // version + mainJarVersion.addSourceProjects(incommingJarVersion.getSourceProjects()); + } + // increment the ref count + mainJarVersion.incrRefCount(); + }); + }); + } + + private void addAllDependencies(JarTree incommingJarTree) { + // for every incoming jar file get the jar file from the main tree, then the + // versions, then the dependencies + incommingJarTree.values().stream().flatMap(incommingJarFile -> incommingJarFile.values().stream()) + .flatMap(incommingJarVersion -> incommingJarVersion.getDependsOn().stream()) + .forEach(incommingTreeDependency -> { + // the dependency will reference the original jar tree jar versions, but we need + // the main tree versions + // so need to get the main tree version entries + String incommingSourceJarVersionName = incommingTreeDependency.getSource().toString(); + IdentifiedJarVersion mainTreeSourceJarVersion = projectJarVersions + .get(incommingSourceJarVersionName.trim()); + if (mainTreeSourceJarVersion == null) { + log.severe("Cannot locate the version " + incommingSourceJarVersionName + + " in the main tree, but it should be there"); + return; + } + String incommingTargetJarVersionName = incommingTreeDependency.getTarget().toString(); + IdentifiedJarVersion mainTreeTargetJarVersion = projectJarVersions + .get(incommingTargetJarVersionName.trim()); + if (mainTreeTargetJarVersion == null) { + log.severe("Cannot locate the version " + incommingTargetJarVersionName + + " in the main tree, but it should be there"); + return; + } + // we have the matching source and dest, let's create a new dependency for them + Dependency mainTreeDependency = incommingTreeDependency.dupeCore(mainTreeSourceJarVersion, + mainTreeTargetJarVersion); + // add the dependency + mainTreeSourceJarVersion.getDependsOn().add(mainTreeDependency); + mainTreeTargetJarVersion.getDependsOnThis().add(mainTreeDependency); + }); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/OptionsData.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/OptionsData.java new file mode 100644 index 0000000..1fee8c3 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/OptionsData.java @@ -0,0 +1,67 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +import java.io.File; +import java.util.List; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; + +import lombok.Data; + +@Data +public class OptionsData { + @Option(name = "-V", aliases = "--Verbose", usage = "Set to true to enable verpose output of intermediate stages (e.g. the mvn sub processes). Defaults to false", metaVar = "true or false") + public boolean verboseOutput = false; + @Option(name = "-d", aliases = "--directory", usage = "Name of the temporary directory to use when generating temp files. Defaults to the current directory if not specified") + public File workingDirectory = new File("."); + @Option(name = "-g", aliases = "--groupid", usage = "The group Id to use for in the root of the combined dependency tree", metaVar = "my.group.id") + public String groupid = "my.company"; + @Option(name = "-a", aliases = "--artifactid", usage = "The artifact Id to use for in the root of the combined dependency tree", metaVar = "codeproject") + public String artifactid = "myartifact"; + @Option(name = "-v", aliases = "--version", usage = "The version to use for in the root of the combined dependency tree", metaVar = "1.2.3+SP2") + public String version = "0.0.0"; + @Option(name = "-m", aliases = "--maven-path", usage = "The version to use for in the root of the combined dependency tree", metaVar = "1.2.3+SP2") + public File mvnPath = null; + @Option(name = "-r", aliases = "--resolve-dependencies", usage = "Set to enable mvn dependency resolution before building the dependency tree, default to false.", metaVar = "true or false") + public boolean resolveDependencies = false; + @Option(name = "-i", aliases = "--retain-intermediates", usage = "Set to true to retain the intermediate files, default to false", metaVar = "true or false") + public boolean retainIntermediateFiles = false; + @Argument(required = true, usage = "Input(s) can be pom.xml, mvn graph outputs (suffix .mvn-graphml)") + public List sources; +} \ No newline at end of file diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/ScopeType.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/ScopeType.java new file mode 100644 index 0000000..4519a8d --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/ScopeType.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser; + +public enum ScopeType { + ROOT, PROJECT, COMPILE, PROVIDED, RUNTIME, TEST, SYSTEM, IMPORT, UNKNOWN, ERROR, INPUT; + + public static ScopeType getScope(String scopeName) { + ScopeType scope = ScopeType.valueOf(scopeName.toUpperCase()); + if (scope == null) { + scope = UNKNOWN; + } + return scope; + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/GetSourceLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/GetSourceLoader.java new file mode 100644 index 0000000..b128ede --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/GetSourceLoader.java @@ -0,0 +1,79 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; +import com.oracle.timg.demo.dependencyanalyser.OptionsData; + +public class GetSourceLoader { + + public static final String POM_XML = "pom.xml"; + public final static String MAVEN_GRAPH_FILE_SUFFIX = ".mvn-graphml.xml"; + public final static String JAR_FILE_SUFFIX = ".jar"; + + public static SourceLoader getSourceLoader(OptionsData options, File source) throws DependencyProcessorException { + if (!source.exists()) { + throw new DependencyProcessorException( + "Source file " + source.getAbsolutePath() + " does not exist, cannot process it"); + } + if (!source.isFile()) { + throw new DependencyProcessorException( + "Source file " + source.getAbsolutePath() + " is not a file, cannot process it"); + } + if (!source.canRead()) { + throw new DependencyProcessorException( + "Source file " + source.getAbsolutePath() + " is not readable, cannot process it"); + } + // need to work out what type of source this is. + String sourceName = source.getName(); + if (sourceName.equalsIgnoreCase(POM_XML)) { + return new MavenPomXMLLoader(options); + } + // if it's a graphml file we can process it instantly + if (source.getName().endsWith(MAVEN_GRAPH_FILE_SUFFIX)) { + return new MavenGraphLoader(options); + } + // if it's a graphml file we can process it instantly + if (source.getName().endsWith(JAR_FILE_SUFFIX)) { + return new JarFileLoader(options); + } + throw new DependencyProcessorException("Unable to locate a loader for file type " + sourceName); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFIleProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFIleProcessorException.java new file mode 100644 index 0000000..7c356de --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFIleProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class JarFIleProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public JarFIleProcessorException() { + super(); + } + + public JarFIleProcessorException(String arg0) { + super(arg0); + } + + public JarFIleProcessorException(Throwable arg0) { + super(arg0); + } + + public JarFIleProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public JarFIleProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFileLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFileLoader.java new file mode 100644 index 0000000..298c4d6 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/JarFileLoader.java @@ -0,0 +1,186 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Optional; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.JarTree; +import com.oracle.timg.demo.dependencyanalyser.OptionsData; + +import lombok.extern.java.Log; + +@Log +public class JarFileLoader extends MavenPomXMLLoader { + public final static String ALLOWABLE_CHARACTERS = "[\\w\\.]"; + + public JarFileLoader(OptionsData optionsData) throws DependencyProcessorException { + super(optionsData); + } + + @Override + public JarTree loadDependencyTree(File sourceFile, File origionalSourceFile) throws DependencyProcessorException { + // will need this later + File tempPomXMLFile; + // try and locate the pom.properties in the jar file, this is the simplest + // option + try (JarFile jarFile = new JarFile(sourceFile);) { + // regexp to locate the pom.properties it will be named along the lines of + // META-INF/maven///pom.properties + // make this final so the lambda doesn't get upset + final Pattern pomPropertiesPattern = Pattern.compile( + "META-INF/maven/" + ALLOWABLE_CHARACTERS + "*/" + ALLOWABLE_CHARACTERS + "*/pom.properties", + Pattern.CASE_INSENSITIVE); + // try to locate the pom.properties file entry + Optional pomPropertiesEntry = jarFile.stream().filter(entry -> { + Matcher matcher = pomPropertiesPattern.matcher(entry.getName()); + return matcher.find(); + }).findFirst(); + // the pom.xml will be similar + final Pattern pomXMLPattern = Pattern.compile( + "META-INF/maven/" + ALLOWABLE_CHARACTERS + "*/" + ALLOWABLE_CHARACTERS + "*/pom.xml", + Pattern.CASE_INSENSITIVE); + // try to locate the pom.properties file entry + Optional pomXMLEntry = jarFile.stream().filter(entry -> { + Matcher matcher = pomXMLPattern.matcher(entry.getName()); + return matcher.find(); + }).findFirst(); + // if we have the pom.properties then get the pom info form that, it's "safer" + IdentifiedJarVersion jarFileIdentifiedJarVerion = null; + if (pomPropertiesEntry.isPresent()) { + ZipEntry pomPropertiesZipFile = pomPropertiesEntry.get(); + try { + MavenPomPropertiesExtractor pomPropertiesExtractor = new MavenPomPropertiesExtractor( + jarFile.getInputStream(pomPropertiesZipFile)); + jarFileIdentifiedJarVerion = pomPropertiesExtractor.getJarVersion(); + log.fine("Extracted pom info " + jarFileIdentifiedJarVerion + " from pom.properties in jar file " + + sourceFile.getPath()); + } catch (MavenPomPropertiesProcessorException e) { + log.fine("Problem loading the pom properties because " + e.getLocalizedMessage()); + } + } + // if we loaded the jar details then we will use them later, but if we didn't + // then fall back to trying to get them from the pom + if (jarFileIdentifiedJarVerion == null) { + if (pomXMLEntry.isEmpty()) { + throw new JarFIleProcessorException("Unfortunately jar file " + sourceFile.getPath() + + " does not containe a usable pom.properties file or pom.xml file, cannot process this jar file"); + } + ZipEntry pomXMLZipFile = pomXMLEntry.get(); + try { + MavenPomXMLExtractor pomXMLExtractor = new MavenPomXMLExtractor( + jarFile.getInputStream(pomXMLZipFile)); + jarFileIdentifiedJarVerion = pomXMLExtractor.getJarVersion(); + log.fine("Extracted pom info " + jarFileIdentifiedJarVerion + " from pom.xml in jar file " + + sourceFile.getPath()); + } catch (XMLProcessorException e) { + throw new JarFIleProcessorException("Unfortunately jar file " + sourceFile.getPath() + + " does not have a usable pom.xml file, cannot process this jar file"); + } + } + + if (jarFileIdentifiedJarVerion == null) { + throw new JarFIleProcessorException("Unfortunately jar file " + sourceFile.getPath() + + " does not have a usable pom.xml or pom.properties file, cannot process this jar file"); + } + // have to check for the pom file directly as we may have gotten the info from + // the pom.properties file + if (pomXMLEntry.isEmpty()) { + throw new JarFIleProcessorException("Unfortunately jar file " + sourceFile.getPath() + + " does not containe a pom.xml file, cannot process this jar file"); + } + // build a name for the pom.xml file to cache + String prefix = jarFileIdentifiedJarVerion.getParent().getGroupId() + "." + + jarFileIdentifiedJarVerion.getParent().getArtifactId() + "-" + + jarFileIdentifiedJarVerion.getVersion() + "-"; + Path pomXMLPath; + try { + pomXMLPath = Files.createTempFile(optionsData.getWorkingDirectory().toPath(), prefix, + "." + GetSourceLoader.POM_XML); + } catch (IOException e) { + throw new JarFIleProcessorException( + "Can't create temp file for pom.xml output in " + optionsData.getWorkingDirectory() + + " using prefix " + prefix + " and suffix " + "." + GetSourceLoader.POM_XML); + } + + tempPomXMLFile = pomXMLPath.toFile(); + String tempPomXMLFileName = tempPomXMLFile.getAbsolutePath(); + // if needed mark this as something to delete when the JVM closes + if (!optionsData.isRetainIntermediateFiles()) { + tempPomXMLFile.deleteOnExit(); + log.info("Will delete temp pom.xml file " + tempPomXMLFileName + " on exit"); + } else { + log.info("Will retain temp pom.xml file " + tempPomXMLFileName + " on exit"); + } + ZipEntry pomXMLZipFile = pomXMLEntry.get(); + log.finer("Pom.xml file in " + pomXMLZipFile + " is of path " + pomXMLZipFile.getName() + " and " + + pomXMLZipFile.getSize() + " bytes long when uncompressed"); + InputStream pomXmlInputStream; + try { + pomXmlInputStream = jarFile.getInputStream(pomXMLZipFile); + } catch (IOException e) { + throw new JarFIleProcessorException( + "Unable to get the pom.xml input stream from " + sourceFile.getPath() + + " because of IO problem " + e.getMessage() + ", cannot process this jar file"); + } + try { + Files.copy(pomXmlInputStream, pomXMLPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new JarFIleProcessorException("Unable to extract the pom.xml file from " + sourceFile.getPath() + + " because of IO problem " + e.getMessage() + ", cannot process this jar file"); + } + } catch (IOException e) { + throw new JarFIleProcessorException( + "IO problem loading the jar file " + sourceFile.getPath() + ", " + e.getLocalizedMessage()); + } + // we have the pom.xml extracted in the temp files. now get the superclass to + // process it + return super.loadDependencyTree(tempPomXMLFile); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphLoader.java new file mode 100644 index 0000000..d6cfc50 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphLoader.java @@ -0,0 +1,295 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.xml.xpath.XPathExpression; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.oracle.timg.demo.dependencyanalyser.Dependency; +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarFile; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.JarTree; +import com.oracle.timg.demo.dependencyanalyser.OptionsData; +import com.oracle.timg.demo.dependencyanalyser.ScopeType; + +import lombok.NonNull; +import lombok.extern.java.Log; + +/** + * Loads the graph output of maven into the jartree to generate the mvn grapu : + * 'mvn -f dependency:tree -DoutputType=graphml -DoutputFile=' Always write the output to a file, dumping it to std out is a + * prioblem as mvn puts a bunch or + */ +@Log +public class MavenGraphLoader implements SourceLoader, XMLLoader { + public final static String GRAPH_ELEMENT_NAME = "graph"; + public final static String DATA_ELEMENT_NAME = "data"; + public final static String NODE_ELEMENT_NAME = "node"; + public final static String EDGE_ELEMENT_NAME = "edge"; + public final static String SHAPE_NODE_ELEMENT_NAME = "ShapeNode"; + public final static String NODE_LABEL_ELEMENT_NAME = "NodeLabel"; + public final static String SOURCE_ATTRIBUTE_NAME = "source"; + public final static String TARGET_ATTRIBUTE_NAME = "target"; + public final static String POLY_LINE_EDGE_ELEMENT_NAME = "PolyLineEdge"; + public final static String EDGE_LABEL_ELEMENT_NAME = "EdgeLabel"; + + // the xpaths we care about + private final XPathExpression ALL_GRAPHS_XPATH, ALL_NODES_XPATH, ALL_EDGES_XPATH, NODE_DATA_SHAPE_NODE_XPATH, + EDGE_DATA_POLY_EDGE_LABEL_XPATH; + // stash this for now in case in the future we need to look into it + protected final OptionsData optionsData; + + public MavenGraphLoader(OptionsData optionsData) throws XMLProcessorException { + this.optionsData = optionsData; + // have to do this here rather than in the variables declaration to handle the + // exceptions + ALL_GRAPHS_XPATH = compileXPath("//" + GRAPH_ELEMENT_NAME); + // these two are relative to the graph so need a relative xpath + ALL_NODES_XPATH = compileXPath("./" + NODE_ELEMENT_NAME); + ALL_EDGES_XPATH = compileXPath("./" + EDGE_ELEMENT_NAME); + NODE_DATA_SHAPE_NODE_XPATH = compileXPath( + "./" + DATA_ELEMENT_NAME + "/" + SHAPE_NODE_ELEMENT_NAME + "/" + NODE_LABEL_ELEMENT_NAME); + EDGE_DATA_POLY_EDGE_LABEL_XPATH = compileXPath( + "./" + DATA_ELEMENT_NAME + "/" + POLY_LINE_EDGE_ELEMENT_NAME + "/" + EDGE_LABEL_ELEMENT_NAME); + } + + @Override + public JarTree loadDependencyTree(File sourceFile, File origionalSourceFile) throws DependencyProcessorException { + JarTree jarTree = new JarTree(origionalSourceFile); + Map idsToJarVersion = new HashMap<>(); + int jarNodesCount = 0; + int dependencyCount = 0; + int processedNodes = 0; + int processedDependencies = 0; + Document document; + try { + document = readXMLDocumentFromFile(sourceFile); + } catch (XMLProcessorException e) { + throw new MavenGraphProcessorException("Problem loading the Maven graphxml file " + sourceFile.getPath(), + e); + } + Element documentRoot = document.getDocumentElement(); + log.fine("Document root is " + documentRoot.getNodeName()); + NodeList graphs = getNodeListByXPath(documentRoot, ALL_GRAPHS_XPATH); + log.fine("There are " + graphs.getLength() + "+ graphs in the document"); + // seems that the xml stuff doesn't support iterators or anything useful so have + // to do this the old fashioned way + for (int graphCounter = 0; graphCounter < graphs.getLength(); graphCounter++) { + Node graph = graphs.item(graphCounter); + if (graph.getNodeType() == Node.ELEMENT_NODE) { + Element graphElement = (Element) graph; + String graphId = graphElement.getAttribute("id"); + NodeList graphNodes = getNodeListByXPath(graphElement, ALL_NODES_XPATH);// graphElement.getElementsByTagName("node"); + jarNodesCount = graphNodes.getLength(); + NodeList graphEdges = getNodeListByXPath(graphElement, ALL_EDGES_XPATH);// graphElement.getElementsByTagName("edge"); + dependencyCount = graphEdges.getLength(); + log.info( + "Graph " + graphId + " contains " + jarNodesCount + " nodes and " + dependencyCount + " edges"); + // first create entries for each of the nodes, this will be a IdentifiedJarFile + // and then a + // IdentifiedJarVersion. at this point we aren't linking them + for (int nodeCounter = 0; nodeCounter < graphNodes.getLength(); nodeCounter++) { + Node jarNode = graphNodes.item(nodeCounter); + if (jarNode.getNodeType() == Node.ELEMENT_NODE) { + processedNodes++; + addJarNode(sourceFile, jarTree, idsToJarVersion, (Element) jarNode); + } else { + log.warning("Node " + jarNode + " should be jar file details, but it's not"); + } + } + for (int dependencyCounter = 0; dependencyCounter < graphEdges.getLength(); dependencyCounter++) { + Node dependencyNode = graphEdges.item(dependencyCounter); + if (dependencyNode.getNodeType() == Node.ELEMENT_NODE) { + processedDependencies++; + addDependency(sourceFile, jarTree, idsToJarVersion, (Element) dependencyNode); + } else { + log.warning("Node " + dependencyNode + " should be dependency details, but it's not"); + } + } + log.fine("Graph " + graphId + " Processed : " + processedNodes + " jar files with " + jarTree.size() + + " jar files added"); + log.fine("Graph " + graphId + " Processed : " + processedDependencies); + } + } + // look for the root, this will have nothing depending on it + Set noDependedOn = jarTree.getJarVersionsWithNoDependOn(); + if (noDependedOn.size() == 0) { + log.severe("Danger, unable to locate a jar version with no dependencies, this jar tree is unusable"); + return null; + } + if (noDependedOn.size() >= 2) { + log.warning( + "There are multiple jar versions which have nothing depending on them, selecting the first as the root, this may not be valid"); + } + jarTree.setRoot(noDependedOn.toArray(new IdentifiedJarVersion[0])[0]); + return jarTree; + } + + private void addJarNode(@NonNull File sourceFile, @NonNull JarTree jarTree, + Map idsToJarVersion, @NonNull Element jarNode) throws XMLProcessorException { + // node data looks like this io.helidon.common.features:helidon-common-features:jar:4.0.6:compile + // get the id + String versionId = jarNode.getAttribute("id").trim(); + NodeList nodeLabelList = getNodeListByXPath(jarNode, NODE_DATA_SHAPE_NODE_XPATH); + Node nodeLabelNode = nodeLabelList.item(0); + String jarInfo = nodeLabelNode.getTextContent().trim(); + String[] jarInfoSplit = jarInfo.split(":"); + if (jarInfoSplit.length < 4) { + log.warning("Jar details " + jarInfo + "+ in node " + jarNode.getTextContent() + + " does not containe the minimum required 4 fields"); + return; + } + String groupId = jarInfoSplit[0]; + String artifactId = jarInfoSplit[1]; + // unknown what options there are for type + String type = jarInfoSplit[2]; + String version = jarInfoSplit[3]; + // the scope is part of the jar info, but I can;t see why as it's the dependency + // elements that count for it. if it's missing then just set to unknown + String scopeString = jarInfoSplit.length >= 5 ? jarInfoSplit[4] : "unknown"; + ScopeType scopeType; + try { + scopeType = ScopeType.getScope(scopeString); + } catch (IllegalArgumentException e) { + log.fine("Loading graphml data from " + sourceFile.getAbsolutePath() + ", node with id " + versionId + + " scope " + scopeString + " is not a known scope, defaulting to " + ScopeType.UNKNOWN); + scopeType = ScopeType.UNKNOWN; + } + + // we know what the jar stuff looks like, let's try and find it + + // now save the jar file in the map under it's id + String jarFileInfo = IdentifiedJarFile.processString(groupId, artifactId).trim(); + // do we have this already ? + IdentifiedJarFile identifiedJarFile = jarTree.get(jarFileInfo.trim()); + if (identifiedJarFile == null) { + // no existing entry create it + identifiedJarFile = new IdentifiedJarFile(groupId, artifactId); + jarTree.put(jarFileInfo.trim(), identifiedJarFile); + } + // does the jar file have this version ? + IdentifiedJarVersion identifiedJarVersion = identifiedJarFile.get(version.trim()); + if (identifiedJarVersion == null) { + identifiedJarVersion = new IdentifiedJarVersion(version, identifiedJarFile, type, scopeType); + identifiedJarVersion.addSourceProject(jarTree); + identifiedJarFile.put(version.trim(), identifiedJarVersion); + } + // save the info away to grab it later when the dependencies are processed + IdentifiedJarVersion oldJarVersion = idsToJarVersion.put(versionId.trim(), identifiedJarVersion); + if (oldJarVersion != null) { + log.severe("Jar version with id " + versionId + + " was already in the map, this is an export error\nOrigional Jar Version " + oldJarVersion + + "\nNew Jar version " + identifiedJarVersion); + } + } + + private void addDependency(@NonNull File sourceFile, JarTree jarTree, + Map idsToJarVersion, Element jarDependency) + throws MavenGraphProcessorException { + // now let's scan the list of dependencies and pull those together + // the dependencies are simpler + // compile + // we care about are the source and target and the label (compile etc) as that's + // the scope info + String sourceId = jarDependency.getAttribute(SOURCE_ATTRIBUTE_NAME); + if (sourceId == null) { + log.warning("Dependency " + jarDependency.getTextContent() + " does not include a source attribute"); + } + + String targetId = jarDependency.getAttribute(TARGET_ATTRIBUTE_NAME); + if (targetId == null) { + log.warning("Dependency " + jarDependency.getTextContent() + " does not include a target attribute"); + } + NodeList targetlList; + try { + targetlList = getNodeListByXPath(jarDependency, EDGE_DATA_POLY_EDGE_LABEL_XPATH); + } catch (XMLProcessorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + if (targetlList.getLength() == 0) { + log.warning("Node " + jarDependency.getTextContent() + " " + DATA_ELEMENT_NAME + " " + + POLY_LINE_EDGE_ELEMENT_NAME + " section does not include a " + EDGE_LABEL_ELEMENT_NAME + + " section"); + return; + } + Node edgeLabelNode = targetlList.item(0); + String edgeLabelText = edgeLabelNode.getTextContent(); + + // try and locate the source and target jar versions + IdentifiedJarVersion sourceJarVersion = idsToJarVersion.get(sourceId.trim()); + if (sourceJarVersion == null) { + log.warning("Dependency " + jarDependency.getTextContent() + " has a source id which is not known"); + return; + } + IdentifiedJarVersion targetJarVersion = idsToJarVersion.get(targetId.trim()); + if (targetJarVersion == null) { + log.warning("Dependency " + jarDependency.getTextContent() + " has a target id which is not known"); + return; + } + ScopeType dependencyScope; + try { + dependencyScope = ScopeType.getScope(edgeLabelText); + } catch (IllegalArgumentException e) { + log.warning("Loading graphml data from " + sourceFile.getAbsolutePath() + ", edge with sourceId " + sourceId + + " to target id " + targetId + " scope " + edgeLabelText + " is not a known scope, defaulting to " + + ScopeType.UNKNOWN); + dependencyScope = ScopeType.UNKNOWN; + } + // create the dependency info, this will seutp the links in the source and + // target for us as well. + Dependency dependency = new Dependency(sourceJarVersion, targetJarVersion, dependencyScope); + // add the dependencies in place + sourceJarVersion.getDependsOn().add(dependency); + targetJarVersion.getDependsOnThis().add(dependency); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphProcessorException.java new file mode 100644 index 0000000..18fc324 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenGraphProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class MavenGraphProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public MavenGraphProcessorException() { + super(); + } + + public MavenGraphProcessorException(String arg0) { + super(arg0); + } + + public MavenGraphProcessorException(Throwable arg0) { + super(arg0); + } + + public MavenGraphProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public MavenGraphProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomDetailsBuilder.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomDetailsBuilder.java new file mode 100644 index 0000000..1ac584c --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomDetailsBuilder.java @@ -0,0 +1,56 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarFile; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.ScopeType; + +public interface MavenPomDetailsBuilder { + + public default IdentifiedJarVersion buildIdentifiedJarVersion(String groupId, String artifactId, String version) { + return buildIdentifiedJarVersion(groupId, artifactId, version, ScopeType.INPUT); + } + + public default IdentifiedJarVersion buildIdentifiedJarVersion(String groupId, String artifactId, String version, + ScopeType scope) { + IdentifiedJarFile identifiedJarFile = new IdentifiedJarFile(groupId, artifactId); + IdentifiedJarVersion identifiedJarVersion = new IdentifiedJarVersion(version, identifiedJarFile, + scope.toString(), scope); + return identifiedJarVersion; + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesExtractor.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesExtractor.java new file mode 100644 index 0000000..7f95232 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesExtractor.java @@ -0,0 +1,92 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.ScopeType; + +import lombok.NonNull; + +public class MavenPomPropertiesExtractor implements XMLLoader, MavenPomDetailsBuilder { + public final static String GROUP_ID_NAME = "groupId"; + public final static String ARTIFACT_ID_NAME = "artifactId"; + public final static String VERSION_NAME = "version"; + private Properties pomProperties = new Properties(); + + public MavenPomPropertiesExtractor(@NonNull File sourceInputFile) + throws MavenPomPropertiesProcessorException, FileNotFoundException { + this(new FileInputStream(sourceInputFile)); + } + + public MavenPomPropertiesExtractor(@NonNull InputStream sourceInputStream) + throws MavenPomPropertiesProcessorException { + try { + pomProperties.load(sourceInputStream); + } catch (IOException e) { + throw new MavenPomPropertiesProcessorException( + "Unable to load the pom properties from the provided input stream because " + + e.getLocalizedMessage()); + } + } + + public IdentifiedJarVersion getJarVersion() throws MavenPomPropertiesProcessorException { + String groupId = pomProperties.getProperty(GROUP_ID_NAME); + if (groupId == null) { + throw new MavenPomPropertiesProcessorException( + "Can't locate " + GROUP_ID_NAME + " in the pom properties input"); + } + String artifactId = pomProperties.getProperty(ARTIFACT_ID_NAME); + if (artifactId == null) { + throw new MavenPomPropertiesProcessorException( + "Can't locate " + ARTIFACT_ID_NAME + " in the pom properties input"); + } + String version = pomProperties.getProperty(VERSION_NAME); + if (version == null) { + throw new MavenPomPropertiesProcessorException( + "Can't locate " + VERSION_NAME + " in the pom properties input"); + } + return buildIdentifiedJarVersion(groupId, artifactId, version, ScopeType.INPUT); + + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesProcessorException.java new file mode 100644 index 0000000..f42d856 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomPropertiesProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class MavenPomPropertiesProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public MavenPomPropertiesProcessorException() { + super(); + } + + public MavenPomPropertiesProcessorException(String arg0) { + super(arg0); + } + + public MavenPomPropertiesProcessorException(Throwable arg0) { + super(arg0); + } + + public MavenPomPropertiesProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public MavenPomPropertiesProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLExtractor.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLExtractor.java new file mode 100644 index 0000000..2118905 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLExtractor.java @@ -0,0 +1,181 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; +import java.io.InputStream; + +import javax.xml.xpath.XPathExpression; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.ScopeType; + +import lombok.NonNull; +import lombok.extern.java.Log; + +@Log +public class MavenPomXMLExtractor implements XMLLoader, MavenPomDetailsBuilder { + public final static String PARENT_NAME = "parent"; + public final static String PROPERTIES_NAME = "properties"; + public final static String GROUP_ID_NAME = "groupId"; + public final static String ARTIFACT_ID_NAME = "artifactId"; + public final static String VERSION_NAME = "version"; + private static XPathExpression GROUP_ID_XPATH, ARTIFACT_ID_XPATH, VERSION_XPATH; + private static XPathExpression GROUP_ID_PARENT_XPATH, ARTIFACT_ID_PARENT_XPATH, VERSION_PARENT_XPATH; + private Document document; + private Element documentRoot; + private String sourceName; + + private MavenPomXMLExtractor(String sourceName) throws XMLProcessorException { + this.sourceName = sourceName; + // only need these once + if (GROUP_ID_XPATH == null) { + GROUP_ID_XPATH = compileXPath("./" + GROUP_ID_NAME); + ARTIFACT_ID_XPATH = compileXPath("./" + ARTIFACT_ID_NAME); + VERSION_XPATH = compileXPath("./" + VERSION_NAME); + GROUP_ID_PARENT_XPATH = compileXPath("./" + PARENT_NAME + "/" + GROUP_ID_NAME); + ARTIFACT_ID_PARENT_XPATH = compileXPath("./" + PARENT_NAME + "/" + ARTIFACT_ID_NAME); + VERSION_PARENT_XPATH = compileXPath("./" + PARENT_NAME + "/" + VERSION_NAME); + } + } + + public MavenPomXMLExtractor(@NonNull File sourceFile) throws XMLProcessorException { + this(sourceFile.getAbsolutePath()); + document = readXMLDocumentFromFile(sourceFile); + documentRoot = document.getDocumentElement(); + } + + public MavenPomXMLExtractor(@NonNull InputStream sourceInputStream) throws XMLProcessorException { + this("Source is input stream"); + document = readXMLDocumentFromFile(sourceInputStream); + documentRoot = document.getDocumentElement(); + } + + public IdentifiedJarVersion getJarVersion() throws XMLProcessorException { + // maven allows you to inherit any of groupid, artifactid or version from the + // parent, though it also seems that some IDE's (e.g. eclipse) require at least + // one of groupId or artifactId to be set for the actuall artifact + String groupId = getNodeContentsByXPath(documentRoot, GROUP_ID_XPATH); + if (groupId == null) { + // try to get the parent artifact id and use that + groupId = getNodeContentsByXPath(documentRoot, GROUP_ID_PARENT_XPATH); + if (groupId == null) { + throw new XMLProcessorException("Can't locate " + GROUP_ID_NAME + + " in the document (not set for the pom.xml for the artifact or parent"); + } + log.finer("for " + sourceName + " Located " + GROUP_ID_NAME + " in parent details"); + } else { + log.finer("for " + sourceName + " Located " + GROUP_ID_NAME + " in artifact details"); + } + String artifactId = getNodeContentsByXPath(documentRoot, ARTIFACT_ID_XPATH); + if (artifactId == null) { + // try to get the parent artifact id and use that + artifactId = getNodeContentsByXPath(documentRoot, ARTIFACT_ID_PARENT_XPATH); + if (artifactId == null) { + throw new XMLProcessorException("Can't locate " + ARTIFACT_ID_NAME + + " in the document (not set for the pom.xml for the artifact or parent"); + } + log.finer("for " + sourceName + " Located " + ARTIFACT_ID_NAME + " in parent details"); + } else { + log.finer("for " + sourceName + " Located " + ARTIFACT_ID_NAME + " in artifact details"); + } + String version = getNodeContentsByXPath(documentRoot, VERSION_XPATH); + if (version == null) { + // try to get the parent version and use that + version = getNodeContentsByXPath(documentRoot, VERSION_PARENT_XPATH); + if (version == null) { + throw new XMLProcessorException("Can't locate " + VERSION_NAME + + " in the document (not set for the pom.xml for the artifact or parent"); + } + log.finer("for " + sourceName + " Located " + VERSION_NAME + " in parent details"); + } else { + log.finer("for " + sourceName + " Located " + VERSION_NAME + " in artifact details"); + } + return buildIdentifiedJarVersion(groupId, artifactId, version, ScopeType.INPUT); + } + + public String getVariable(String varName) throws XMLProcessorException { + // if it's an absolute path just go to it + String varValue = null; + if (varName.startsWith("/") || varName.startsWith(".")) { + return getNodeContentsByXPath(documentRoot, compileXPath(varName)); + } + // OK it's not an absolute or relative path + // try looking in the properties + String varPath = "/" + PROPERTIES_NAME + "/" + varName; + varValue = getNodeContentsByXPath(documentRoot, compileXPath(varPath)); + if (varValue != null) { + return varValue; + } + // that didn't work, try looking in general from the root (e.g. it's + // parent.version) + varValue = getNodeContentsByXPath(documentRoot, compileXPath("/" + varName)); + // result will be null or the value + return varValue; + } + + public String getXPathWithVarSubstitution(String xPath) throws XMLProcessorException { + String value = getNodeContentsByXPath(documentRoot, compileXPath(xPath)); + // if it wasn't there return null + if (value == null) { + return null; + } + // if it is there AND starts with ${ and ends with } then try and lookup the + // value + if (!(value.startsWith("${") && value.endsWith("}"))) { + // it's not a variable, return it directly + return value; + } + // try and get it as a property + String varName = value.substring(2, value.length() - 1); + String varPath = "/" + PROPERTIES_NAME + "/" + varName; + value = getNodeContentsByXPath(document, compileXPath(varPath)); + + if (value != null) { + // we found is in the properties + return value; + } + // that didn't work but it's still a variable, try looking for the variable name + // in the general document + value = getNodeContentsByXPath(document, compileXPath(varName)); + // result will be null or the value + return value; + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLLoader.java new file mode 100644 index 0000000..eb284d9 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLLoader.java @@ -0,0 +1,239 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +import com.kazurayam.subprocessj.Subprocess; +import com.kazurayam.subprocessj.Subprocess.CompletedProcess; +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarFile; +import com.oracle.timg.demo.dependencyanalyser.IdentifiedJarVersion; +import com.oracle.timg.demo.dependencyanalyser.JarTree; +import com.oracle.timg.demo.dependencyanalyser.OptionsData; +import com.oracle.timg.demo.dependencyanalyser.ScopeType; + +import lombok.extern.java.Log; + +/** + * Loads the graph output of maven into the jartree to generate the mvn grapu : + * 'mvn -f dependency:tree -DoutputType=graphml -DoutputFile=' Always write the output to a file, dumping it to std out is a + * prioblem as mvn puts a bunch or + */ +@Log +public class MavenPomXMLLoader extends MavenGraphLoader { + public final static String MVN_DEPENDENCY_RESOLVE_CMD = "dependency:resolve"; + public final static String MVN_DEPENDENCY_TREE_CMD = "dependency:tree"; + public final static String MVN_DEPENDENCY_GRAPH_OUTPUT_FLAG = "-DoutputType=graphml"; + public final static String MVN_DEPENDENCY_OUTPUT_FILE_FLAG = "-DoutputFile="; // must be followed by a file name, + // but we can generate a temp one + // for now + // mvn dependency:tree-DoutputType=graphml-DoutputFile=filewriter.txt + protected IdentifiedJarVersion sourceJarVersion; + protected IdentifiedJarFile sourceJarFile; + + public MavenPomXMLLoader(OptionsData optionsData) throws DependencyProcessorException { + super(optionsData); + // we need a maven executable + if (optionsData.mvnPath == null) { + throw new MavenPomXMLProcessorException( + "Processing a pom.xml file requires that path to the maven executable be set"); + } + if (!optionsData.mvnPath.exists()) { + throw new MavenPomXMLProcessorException( + "The maven executable location " + optionsData.mvnPath.getPath() + " does not exist"); + } + if (!optionsData.mvnPath.canExecute()) { + throw new MavenPomXMLProcessorException( + "The maven executable location " + optionsData.mvnPath.getPath() + " is not executable"); + } + // make sure we have a usable working directory we can write to + if (optionsData.workingDirectory == null) { + throw new MavenPomXMLProcessorException("Processing a pom.xml file requires a working directory be set"); + } + if (!optionsData.workingDirectory.exists()) { + throw new MavenPomXMLProcessorException( + "The working directory location " + optionsData.workingDirectory.getPath() + " does not exist"); + } + if (!optionsData.workingDirectory.isDirectory()) { + throw new MavenPomXMLProcessorException( + "The working directory location " + optionsData.workingDirectory.getPath() + " is not a directory"); + } + if (!optionsData.workingDirectory.canWrite()) { + throw new MavenPomXMLProcessorException( + "The working directory location " + optionsData.workingDirectory.getPath() + " is not writable"); + } + if (!optionsData.workingDirectory.canRead()) { + throw new MavenPomXMLProcessorException( + "The working directory location " + optionsData.workingDirectory.getPath() + " is not readable"); + } + + } + + @Override + public JarTree loadDependencyTree(File sourceFile, File origionalSourceFile) throws DependencyProcessorException { + // make sure that the source is there + validateSource(sourceFile); + log.info("Loading the provided maven pom file " + sourceFile.getPath()); + // next we generate the output + // load the pom.xml file to play with + MavenPomXMLExtractor pomExtractor; + try { + pomExtractor = new MavenPomXMLExtractor(sourceFile); + } catch (XMLProcessorException e) { + throw new MavenPomXMLProcessorException("Can't load the maven pom file " + e.getLocalizedMessage(), e); + } + + log.fine("Loading the maven pom project details"); + // get the jar details from it + IdentifiedJarVersion pomDetails; + try { + pomDetails = pomExtractor.getJarVersion(); + } catch (XMLProcessorException e) { + throw new MavenPomXMLProcessorException( + "Can't extract the maven project details " + e.getLocalizedMessage(), e); + } + log.fine("Maven pom core details extracted, result is " + pomDetails); + return loadDependencyTree(sourceFile, origionalSourceFile, pomDetails); + } + + /* + * for some inputs there are other ways to get the details (e.g. in a jar there + * is the pom.properties file which is easier to parse) + */ + public JarTree loadDependencyTree(File sourceFile, String groupId, String artifactId, String version, + File origionalSourceFile) throws DependencyProcessorException { + // make sure that the source is there + validateSource(sourceFile); + IdentifiedJarFile jarFile = new IdentifiedJarFile(groupId, artifactId); + IdentifiedJarVersion pomDetails = new IdentifiedJarVersion(version, jarFile, "InputPom", ScopeType.INPUT); + log.fine("Maven pom core details built, result is " + pomDetails); + return loadDependencyTree(sourceFile, origionalSourceFile, pomDetails); + } + + public JarTree loadDependencyTree(File sourceFile, File origionalSourceFile, IdentifiedJarVersion pomDetails) + throws DependencyProcessorException { + // load the pom.xml file and setup the info on it + // unless they have overridden the dependency resolution flag first resolve the + // dependencies to the local maven cache, that way we know we will have all of + // the contents locally before we then build the graphml file and process it + if (optionsData.isResolveDependencies()) { + // command is dependency:resolve -f + CompletedProcess resolveCP; + try { + List resolveList = Arrays.asList(optionsData.mvnPath.getAbsolutePath(), "-f", + sourceFile.getAbsolutePath(), MVN_DEPENDENCY_RESOLVE_CMD); + if (optionsData.isVerboseOutput()) { + log.info("About to run the following command to resolve the dependencies, this may take a while:\n" + + resolveList); + } + resolveCP = new Subprocess().cwd(new File(".")).run(resolveList); + } catch (IOException | InterruptedException e) { + throw new MavenPomXMLProcessorException( + "mvn dependency resolution did not complete sucesfully, " + e.getLocalizedMessage(), e); + } + if (optionsData.isVerboseOutput()) { + log.info("Maven dependency resolve standard output is :\n" + resolveCP.stdout()); + log.info("Maven dependency resolve error output is :\n" + resolveCP.stderr()); + } + int resolveReturnCode = resolveCP.returncode(); + if (resolveReturnCode != 0) { + throw new MavenPomXMLProcessorException( + "mvn dependency resolution did not complete sucesfully, return code was " + resolveReturnCode); + } + } + // work out where to save the mvn-graphml file, we will include the name details + // in this + String prefix = pomDetails.getParent().getGroupId() + "." + pomDetails.getParent().getArtifactId() + "-" + + pomDetails.getVersion() + "-"; + Path graphMLPath; + try { + graphMLPath = Files.createTempFile(optionsData.getWorkingDirectory().toPath(), prefix, + GetSourceLoader.MAVEN_GRAPH_FILE_SUFFIX); + } catch (IOException e) { + throw new MavenPomXMLProcessorException( + "Can't create temp file for graphml output in " + optionsData.getWorkingDirectory() + + " using prefix " + prefix + " and suffix " + GetSourceLoader.MAVEN_GRAPH_FILE_SUFFIX); + } + File tempGraphMl = graphMLPath.toFile(); + // note that maven seems to set it's working directory to where the pom.xml file + // is, if the location of the graphxml file is relative then maven will if + // needed create directories relative to that. This can mean that the graphxml + // file is generated in an unexpected location. to solve that we use an absolute + // path + String tempGraphMLFileName = tempGraphMl.getAbsolutePath(); + // if needed mark this as something to delete when the JVM closes + if (!optionsData.isRetainIntermediateFiles()) { + tempGraphMl.deleteOnExit(); + log.info("Will delete temp graphml file " + tempGraphMLFileName + " on exit"); + } else { + log.info("Will retain temp graphml file " + tempGraphMLFileName + " on exit"); + } + // build a graph from it + CompletedProcess dependencyTreeCP; + try { + List dependencyList = Arrays.asList(optionsData.mvnPath.getAbsolutePath(), "-f", + sourceFile.getAbsolutePath(), MVN_DEPENDENCY_TREE_CMD, MVN_DEPENDENCY_GRAPH_OUTPUT_FLAG, + MVN_DEPENDENCY_OUTPUT_FILE_FLAG + tempGraphMLFileName); + log.info("About to run the following command to get the dependency tree, this may take a while:\n" + + dependencyList); + dependencyTreeCP = new Subprocess().run(dependencyList); + } catch (IOException | InterruptedException e) { + throw new MavenPomXMLProcessorException( + "mvn dependency resolution did not complete sucesfully, " + e.getLocalizedMessage(), e); + } + if (optionsData.isVerboseOutput()) { + log.info("Maven dependency tree standard output is :\n" + dependencyTreeCP.stdout()); + log.info("Maven dependency tree error output is :\n" + dependencyTreeCP.stderr()); + } + + int dependencyTreeReturnCode = dependencyTreeCP.returncode(); + if (dependencyTreeReturnCode != 0) { + throw new MavenPomXMLProcessorException( + "mvn dependency tree computation did not complete sucesfully, return code was " + + dependencyTreeReturnCode); + } + // now we can get the superclass to operate on the graph output + return super.loadDependencyTree(tempGraphMl, origionalSourceFile); + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLProcessorException.java new file mode 100644 index 0000000..68c8255 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenPomXMLProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class MavenPomXMLProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public MavenPomXMLProcessorException() { + super(); + } + + public MavenPomXMLProcessorException(String arg0) { + super(arg0); + } + + public MavenPomXMLProcessorException(Throwable arg0) { + super(arg0); + } + + public MavenPomXMLProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public MavenPomXMLProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenProcessorException.java new file mode 100644 index 0000000..ab2fc74 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/MavenProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class MavenProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public MavenProcessorException() { + super(); + } + + public MavenProcessorException(String arg0) { + super(arg0); + } + + public MavenProcessorException(Throwable arg0) { + super(arg0); + } + + public MavenProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public MavenProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/SourceLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/SourceLoader.java new file mode 100644 index 0000000..74a038a --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/SourceLoader.java @@ -0,0 +1,66 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.File; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; +import com.oracle.timg.demo.dependencyanalyser.JarTree; + +public interface SourceLoader { + + public default JarTree loadDependencyTree(File sourceFile) throws DependencyProcessorException { + return loadDependencyTree(sourceFile, sourceFile); + } + + public JarTree loadDependencyTree(File sourceFile, File origionalSourceFile) throws DependencyProcessorException; + + public default void validateSource(File sourceFile) throws MavenPomXMLProcessorException { + if (!sourceFile.exists()) { + throw new MavenPomXMLProcessorException( + "The source maven pom file " + sourceFile.getPath() + " does not exist"); + } + if (!sourceFile.isFile()) { + throw new MavenPomXMLProcessorException( + "The source maven pom file " + sourceFile.getPath() + " is not a file"); + } + if (!sourceFile.canRead()) { + throw new MavenPomXMLProcessorException( + "The source maven pom file " + sourceFile.getPath() + " is not readable"); + } + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLLoader.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLLoader.java new file mode 100644 index 0000000..8497bf3 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLLoader.java @@ -0,0 +1,161 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public interface XMLLoader { + public final static XPath xPath = XPathFactory.newInstance().newXPath(); + + public default Document readXMLDocumentFromFile(File sourceFile) throws XMLProcessorException { + System.err.println("Abput to read XML document from " + sourceFile.getPath()); + try { + return readXMLDocumentFromFile(new BufferedInputStream(new FileInputStream(sourceFile))); + } catch (FileNotFoundException e) { + throw new XMLProcessorException("Cant locate file " + sourceFile.getPath()); + } + } + + public default Document readXMLDocumentFromFile(InputStream sourceInputStream) throws XMLProcessorException { + + // Get Document Builder, note that this DOES NOT create namespace aware + // documents as doing so seems to cause problems with xpath + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder; + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new XMLProcessorException("Can't create XML Document parser " + e.getLocalizedMessage(), e); + } + + // Build Document + Document document; + try { + document = builder.parse(sourceInputStream); + } catch (SAXException e) { + throw new XMLProcessorException("XML Document structure exception " + e.getLocalizedMessage(), e); + } catch (IOException e) { + throw new XMLProcessorException("Can't create XML input stream " + e.getLocalizedMessage(), e); + } + + // Normalize the XML Structure; It's just too important !! + document.getDocumentElement().normalize(); + + return document; + } + + public default XPathExpression compileXPath(String xPathExpression) throws XMLProcessorException { + try { + return xPath.compile(xPathExpression); + } catch (XPathExpressionException e) { + throw new XMLProcessorException( + "Specified xpath " + xPathExpression + " has a compile error " + e.getLocalizedMessage()); + } + } + + public default String getNodeContentsByXPath(Node startNode, String xPathExpression) throws XMLProcessorException { + try { + return getNodeContentsByXPath(startNode, xPath.compile(xPathExpression)); + } catch (XPathExpressionException e) { + throw new XMLProcessorException("Provided xpath expression is invalid, " + e.getLocalizedMessage(), e); + } + } + + public default String getNodeContentsByXPath(Node startNode, XPathExpression xPathExpression) + throws XMLProcessorException { + NodeList list = getNodeListByXPath(startNode, xPathExpression); + if (list.getLength() == 0) { + return null; + } + Node n = list.item(0); + return n.getTextContent(); + } + + public default NodeList getNodeListByXPath(Node startNode, String xPathExpression) throws XMLProcessorException { + if (startNode.getNodeType() == Node.ELEMENT_NODE) { + return getNodeListByXPath((Element) startNode, xPathExpression); + } else { + throw new XMLProcessorException("Provided node is not of type element." + startNode.getTextContent()); + } + } + + public default NodeList getNodeListByXPath(Element startNode, String xPathExpression) throws XMLProcessorException { + try { + return getNodeListByXPath(startNode, xPath.compile(xPathExpression)); + } catch (XPathExpressionException e) { + throw new XMLProcessorException("Provided xpath expression is invalid, " + e.getLocalizedMessage(), e); + } + } + + public default NodeList getNodeListByXPath(Node startNode, XPathExpression xPathExpression) + throws XMLProcessorException { + if (startNode.getNodeType() == Node.ELEMENT_NODE) { + return getNodeListByXPath((Element) startNode, xPathExpression); + } else { + throw new XMLProcessorException("Provided node is not of type element." + startNode.getTextContent()); + } + } + + public default NodeList getNodeListByXPath(Element startNode, XPathExpression xPathExpression) + throws XMLProcessorException { + try { + return (NodeList) xPathExpression.evaluate(startNode, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + throw new XMLProcessorException("Problem processing the xpath " + e.getLocalizedMessage(), e); + } + } +} diff --git a/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLProcessorException.java b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLProcessorException.java new file mode 100644 index 0000000..ce88e85 --- /dev/null +++ b/dependencyanalyser/src/main/java/com/oracle/timg/demo/dependencyanalyser/importers/XMLProcessorException.java @@ -0,0 +1,65 @@ +/*Copyright (c) 2024 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.timg.demo.dependencyanalyser.importers; + +import com.oracle.timg.demo.dependencyanalyser.DependencyProcessorException; + +public class XMLProcessorException extends DependencyProcessorException { + + private static final long serialVersionUID = 529077741205885816L; + + public XMLProcessorException() { + super(); + } + + public XMLProcessorException(String arg0) { + super(arg0); + } + + public XMLProcessorException(Throwable arg0) { + super(arg0); + } + + public XMLProcessorException(String arg0, Throwable arg1) { + super(arg0, arg1); + } + + public XMLProcessorException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { + super(arg0, arg1, arg2, arg3); + } + +} diff --git a/dependencyanalyser/testdata/filereader.mvn-graphml.xml b/dependencyanalyser/testdata/filereader.mvn-graphml.xml new file mode 100644 index 0000000..4726d13 --- /dev/null +++ b/dependencyanalyser/testdata/filereader.mvn-graphml.xml @@ -0,0 +1,1857 @@ + + + + + + + + + com.oracle.labs.helidon.fileio:filereader:jar:1.0.0 + + + + + + + + io.helidon.microprofile.bundles:helidon-microprofile-core:jar:4.0.6:compile + + + + + + + + io.helidon.microprofile.server:helidon-microprofile-server:jar:4.0.6:compile + + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.microprofile.cdi:helidon-microprofile-cdi:jar:4.0.6:compile + + + + + + + + io.helidon:helidon:jar:4.0.6:compile + + + + + + + compile + + + + + + + io.helidon.microprofile.weld:weld-se-core:jar:4.0.6:compile + + + + + + + + io.helidon.microprofile.weld:weld-core-impl:jar:4.0.6:compile + + + + + + + + compile + + + + + + + org.jboss.weld.environment:weld-environment-common:jar:5.1.1.SP2:compile + + + + + + + + compile + + + + + + + org.jboss.weld:weld-api:jar:5.0.SP3:compile + + + + + + + + compile + + + + + + + org.jboss.weld:weld-spi:jar:5.0.SP3:compile + + + + + + + + compile + + + + + + + compile + + + + + + + org.jboss.classfilewriter:jboss-classfilewriter:jar:1.3.0.Final:compile + + + + + + + + compile + + + + + + + org.jboss.weld:weld-lite-extension-translator:jar:5.1.1.SP2:compile + + + + + + + + org.jboss.logging:jboss-logging-processor:jar:2.2.1.Final:compile + + + + + + + + org.jboss.logging:jboss-logging-annotations:jar:2.2.1.Final:compile + + + + + + + + compile + + + + + + + org.jboss.jdeparser:jdeparser:jar:2.0.3.Final:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.common.features:helidon-common-features:jar:4.0.6:compile + + + + + + + + io.helidon.common.features:helidon-common-features-api:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.webserver:helidon-webserver:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-socket:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-key-util:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-security:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-task:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-tls:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.http.media:helidon-http-media:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.http.encoding:helidon-http-encoding:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.webserver:helidon-webserver-static-content:jar:4.0.6:compile + + + + + + + + compile + + + + + + + jakarta.enterprise:jakarta.enterprise.cdi-api:jar:4.0.1:compile + + + + + + + + jakarta.enterprise:jakarta.enterprise.lang-model:jar:4.0.1:compile + + + + + + + + compile + + + + + + + jakarta.el:jakarta.el-api:jar:5.0.1:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.http.media:helidon-http-media-jsonp:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.webserver:helidon-webserver-context:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.config:helidon-config:jar:4.0.6:compile + + + + + + + + io.helidon.inject:helidon-inject-api:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-types:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.jersey:helidon-jersey-server:jar:4.0.6:compile + + + + + + + + org.glassfish.jersey.core:jersey-server:jar:3.1.5:compile + + + + + + + + jakarta.validation:jakarta.validation-api:jar:3.0.0:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.config:helidon-config-yaml:jar:4.0.6:compile + + + + + + + + compile + + + + + + + org.glassfish.jersey.ext.cdi:jersey-weld2-se:jar:3.1.5:runtime + + + + + + + + org.glassfish.jersey.ext.cdi:jersey-cdi1x:jar:3.1.5:runtime + + + + + + + + runtime + + + + + + + runtime + + + + + + + io.helidon.jersey:helidon-jersey-media-jsonp:jar:4.0.6:compile + + + + + + + + org.glassfish.jersey.media:jersey-media-json-processing:jar:3.1.5:compile + + + + + + + + org.eclipse.parsson:parsson-media:jar:1.1.5:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.microprofile.config:helidon-microprofile-config:jar:4.0.6:compile + + + + + + + + io.helidon.config:helidon-config-mp:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.config:helidon-config-encryption:jar:4.0.6:runtime + + + + + + + + io.helidon.common:helidon-common-crypto:jar:4.0.6:runtime + + + + + + + + runtime + + + + + + + runtime + + + + + + + io.helidon.config:helidon-config-object-mapping:jar:4.0.6:runtime + + + + + + + + runtime + + + + + + + compile + + + + + + + compile + + + + + + + org.apiguardian:apiguardian-api:jar:1.0.0:compile + + + + + + + + compile + + + + + + + io.helidon.microprofile.openapi:helidon-microprofile-openapi:jar:4.0.6:compile + + + + + + + + io.helidon.openapi:helidon-openapi:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-config:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-mapper:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-media-type:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + org.eclipse.microprofile.config:microprofile-config-api:jar:3.0.3:compile + + + + + + + + compile + + + + + + + org.eclipse.microprofile.openapi:microprofile-openapi-api:jar:3.1.1:compile + + + + + + + + compile + + + + + + + io.helidon.webserver:helidon-webserver-service-common:jar:4.0.6:compile + + + + + + + + io.helidon.webserver:helidon-webserver-cors:jar:4.0.6:compile + + + + + + + + io.helidon.cors:helidon-cors:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.microprofile.service-common:helidon-microprofile-service-common:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.smallrye:smallrye-open-api-core:jar:3.3.4:compile + + + + + + + + org.jboss.logging:jboss-logging:jar:3.5.3.Final:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.smallrye:smallrye-open-api-jaxrs:jar:3.3.4:compile + + + + + + + + compile + + + + + + + org.yaml:snakeyaml:jar:2.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.microprofile.health:helidon-microprofile-health:jar:4.0.6:compile + + + + + + + + org.eclipse.microprofile.health:microprofile-health-api:jar:4.0.1:compile + + + + + + + + compile + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe-health:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.health:helidon-health:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + jakarta.json.bind:jakarta.json.bind-api:jar:3.0.0:compile + + + + + + + + compile + + + + + + + org.glassfish.jersey.media:jersey-media-json-binding:jar:3.1.5:runtime + + + + + + + + org.glassfish.jersey.core:jersey-common:jar:3.1.5:compile + + + + + + + + jakarta.ws.rs:jakarta.ws.rs-api:jar:3.1.0:compile + + + + + + + + compile + + + + + + + jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile + + + + + + + + compile + + + + + + + jakarta.inject:jakarta.inject-api:jar:2.0.1:compile + + + + + + + + compile + + + + + + + org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile + + + + + + + + compile + + + + + + + compile + + + + + + + jakarta.json:jakarta.json-api:jar:2.1.3:compile + + + + + + + + compile + + + + + + + org.eclipse.parsson:parsson:jar:1.1.5:compile + + + + + + + + compile + + + + + + + org.eclipse:yasson:jar:3.0.3:runtime + + + + + + + runtime + + + + + + + runtime + + + + + + + io.helidon.logging:helidon-logging-jul:jar:4.0.6:runtime + + + + + + + + io.helidon.common:helidon-common-context:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.logging:helidon-logging-common:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common:jar:4.0.6:compile + + + + + + + + compile + + + + + + + runtime + + + + + + + io.smallrye:jandex:jar:3.1.2:runtime + + + + + + + runtime + + + + + + + jakarta.activation:jakarta.activation-api:jar:2.1.1:compile + + + + + + + + compile + + + + + + + org.eclipse.microprofile.metrics:microprofile-metrics-api:jar:5.0.1:compile + + + + + + + + jakarta.interceptor:jakarta.interceptor-api:jar:2.1.0:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.microprofile.metrics:helidon-microprofile-metrics:jar:4.0.6:compile + + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe-metrics:jar:4.0.6:compile + + + + + + + + io.helidon.metrics.providers:helidon-metrics-providers-micrometer:jar:4.0.6:compile + + + + + + + + io.micrometer:micrometer-core:jar:1.11.3:compile + + + + + + + + io.micrometer:micrometer-commons:jar:1.11.3:compile + + + + + + + + compile + + + + + + + io.micrometer:micrometer-observation:jar:1.11.3:compile + + + + + + + + compile + + + + + + + org.hdrhistogram:HdrHistogram:jar:2.1.12:runtime + + + + + + + + runtime + + + + + + + org.latencyutils:LatencyUtils:jar:2.0.3:runtime + + + + + + + + runtime + + + + + + + compile + + + + + + + io.micrometer:micrometer-registry-prometheus:jar:1.11.3:compile + + + + + + + + io.prometheus:simpleclient_common:jar:0.16.0:compile + + + + + + + + io.prometheus:simpleclient:jar:0.16.0:compile + + + + + + + + io.prometheus:simpleclient_tracer_otel:jar:0.16.0:compile + + + + + + + + compile + + + + + + + io.prometheus:simpleclient_tracer_otel_agent:jar:0.16.0:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.prometheus:simpleclient_tracer_common:jar:0.16.0:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.metrics:helidon-metrics-api:jar:4.0.6:compile + + + + + + + + io.helidon.http:helidon-http:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-configurable:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-buffers:jar:4.0.6:compile + + + + + + + + compile + + + + + + + io.helidon.common:helidon-common-uri:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-parameters:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.builder:helidon-builder-api:jar:4.0.6:compile + + + + + + + + compile + + + + + + + compile + + + + + + + io.helidon.metrics:helidon-metrics-system-meters:jar:4.0.6:runtime + + + + + + + + runtime + + + + + + + compile + + + + + + + org.junit.jupiter:junit-jupiter-api:jar:5.9.3:test + + + + + + + + org.opentest4j:opentest4j:jar:1.2.0:test + + + + + + + test + + + + + + + org.junit.platform:junit-platform-commons:jar:1.9.3:test + + + + + + + + test + + + + + + + test + + + + + + + io.helidon.microprofile.testing:helidon-microprofile-testing-junit5:jar:4.0.6:test + + + + + + + + io.helidon.jersey:helidon-jersey-client:jar:4.0.6:test + + + + + + + + org.glassfish.jersey.core:jersey-client:jar:3.1.5:compile + + + + + + + + compile + + + + + + + org.glassfish.jersey.inject:jersey-hk2:jar:3.1.5:compile + + + + + + + + org.glassfish.hk2:hk2-locator:jar:3.0.5:compile + + + + + + + + org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.5:compile + + + + + + + + compile + + + + + + + org.glassfish.hk2:hk2-api:jar:3.0.5:compile + + + + + + + + compile + + + + + + + org.glassfish.hk2:hk2-utils:jar:3.0.5:compile + + + + + + + + compile + + + + + + + compile + + + + + + + org.javassist:javassist:jar:3.29.2-GA:compile + + + + + + + + compile + + + + + + + compile + + + + + + + test + + + + + + + io.helidon.config:helidon-config-yaml-mp:jar:4.0.6:compile + + + + + + + + compile + + + + + + + test + + + + + + + org.hamcrest:hamcrest-all:jar:1.3:test + + + + + + + test + + + + + + + org.projectlombok:lombok:jar:1.18.32:provided + + + + + + + + provided + + + + + \ No newline at end of file diff --git a/dependencyanalyser/testdata/filewriter.mvn-graphml.xml b/dependencyanalyser/testdata/filewriter.mvn-graphml.xml new file mode 100644 index 0000000..9503d79 --- /dev/null +++ b/dependencyanalyser/testdata/filewriter.mvn-graphml.xml @@ -0,0 +1,1842 @@ + + + + + + + + + + com.oracle.labs.helidon.fileio:filewriter:jar:1.0.0 + + + + + + + + io.helidon.microprofile.bundles:helidon-microprofile-core:jar:4.0.6:compile + + + + + + + + io.helidon.microprofile.server:helidon-microprofile-server:jar:4.0.6:compile + + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.cdi:helidon-microprofile-cdi:jar:4.0.6:compile + + + + + + + io.helidon:helidon:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.weld:weld-se-core:jar:4.0.6:compile + + + + + + + + io.helidon.microprofile.weld:weld-core-impl:jar:4.0.6:compile + + + + + + + compile + + + + + + + + org.jboss.weld.environment:weld-environment-common:jar:5.1.1.SP2:compile + + + + + + + compile + + + + + + + org.jboss.weld:weld-api:jar:5.0.SP3:compile + + + + + + + compile + + + + + + + org.jboss.weld:weld-spi:jar:5.0.SP3:compile + + + + + + + compile + + + + + + + compile + + + + + + + + org.jboss.classfilewriter:jboss-classfilewriter:jar:1.3.0.Final:compile + + + + + + + compile + + + + + + + + org.jboss.weld:weld-lite-extension-translator:jar:5.1.1.SP2:compile + + + + + + + + org.jboss.logging:jboss-logging-processor:jar:2.2.1.Final:compile + + + + + + + + org.jboss.logging:jboss-logging-annotations:jar:2.2.1.Final:compile + + + + + + + compile + + + + + + + + org.jboss.jdeparser:jdeparser:jar:2.0.3.Final:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.common.features:helidon-common-features:jar:4.0.6:compile + + + + + + + + io.helidon.common.features:helidon-common-features-api:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.webserver:helidon-webserver:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-socket:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-key-util:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-security:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-task:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-tls:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.http.media:helidon-http-media:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.http.encoding:helidon-http-encoding:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.webserver:helidon-webserver-static-content:jar:4.0.6:compile + + + + + + + compile + + + + + + + + jakarta.enterprise:jakarta.enterprise.cdi-api:jar:4.0.1:compile + + + + + + + + jakarta.enterprise:jakarta.enterprise.lang-model:jar:4.0.1:compile + + + + + + + compile + + + + + + + jakarta.el:jakarta.el-api:jar:5.0.1:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.http.media:helidon-http-media-jsonp:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.webserver:helidon-webserver-context:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.config:helidon-config:jar:4.0.6:compile + + + + + + + + io.helidon.inject:helidon-inject-api:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-types:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.jersey:helidon-jersey-server:jar:4.0.6:compile + + + + + + + + org.glassfish.jersey.core:jersey-server:jar:3.1.5:compile + + + + + + + + jakarta.validation:jakarta.validation-api:jar:3.0.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.config:helidon-config-yaml:jar:4.0.6:compile + + + + + + + compile + + + + + + + + org.glassfish.jersey.ext.cdi:jersey-weld2-se:jar:3.1.5:runtime + + + + + + + + org.glassfish.jersey.ext.cdi:jersey-cdi1x:jar:3.1.5:runtime + + + + + + + runtime + + + + + + + runtime + + + + + + + + io.helidon.jersey:helidon-jersey-media-jsonp:jar:4.0.6:compile + + + + + + + + org.glassfish.jersey.media:jersey-media-json-processing:jar:3.1.5:compile + + + + + + + + org.eclipse.parsson:parsson-media:jar:1.1.5:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.config:helidon-microprofile-config:jar:4.0.6:compile + + + + + + + + io.helidon.config:helidon-config-mp:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.config:helidon-config-encryption:jar:4.0.6:runtime + + + + + + + + io.helidon.common:helidon-common-crypto:jar:4.0.6:runtime + + + + + + + runtime + + + + + + + runtime + + + + + + + + io.helidon.config:helidon-config-object-mapping:jar:4.0.6:runtime + + + + + + + runtime + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.openapi:helidon-microprofile-openapi:jar:4.0.6:compile + + + + + + + + io.helidon.openapi:helidon-openapi:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-config:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-mapper:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-media-type:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + + org.eclipse.microprofile.config:microprofile-config-api:jar:3.0.3:compile + + + + + + + compile + + + + + + + + org.eclipse.microprofile.openapi:microprofile-openapi-api:jar:3.1.1:compile + + + + + + + compile + + + + + + + + io.helidon.webserver:helidon-webserver-service-common:jar:4.0.6:compile + + + + + + + + io.helidon.webserver:helidon-webserver-cors:jar:4.0.6:compile + + + + + + + io.helidon.cors:helidon-cors:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.service-common:helidon-microprofile-service-common:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.smallrye:smallrye-open-api-core:jar:3.3.4:compile + + + + + + + + org.jboss.logging:jboss-logging:jar:3.5.3.Final:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.smallrye:smallrye-open-api-jaxrs:jar:3.3.4:compile + + + + + + + compile + + + + + + + org.yaml:snakeyaml:jar:2.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.health:helidon-microprofile-health:jar:4.0.6:compile + + + + + + + + org.eclipse.microprofile.health:microprofile-health-api:jar:4.0.1:compile + + + + + + + compile + + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe-health:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.health:helidon-health:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + + jakarta.json.bind:jakarta.json.bind-api:jar:3.0.0:compile + + + + + + + compile + + + + + + + + org.glassfish.jersey.media:jersey-media-json-binding:jar:3.1.5:runtime + + + + + + + + org.glassfish.jersey.core:jersey-common:jar:3.1.5:compile + + + + + + + + jakarta.ws.rs:jakarta.ws.rs-api:jar:3.1.0:compile + + + + + + + compile + + + + + + + + jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile + + + + + + + compile + + + + + + + + jakarta.inject:jakarta.inject-api:jar:2.0.1:compile + + + + + + + compile + + + + + + + + org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile + + + + + + + compile + + + + + + + compile + + + + + + + jakarta.json:jakarta.json-api:jar:2.1.3:compile + + + + + + + compile + + + + + + + org.eclipse.parsson:parsson:jar:1.1.5:compile + + + + + + + compile + + + + + + + org.eclipse:yasson:jar:3.0.3:runtime + + + + + + + runtime + + + + + + + runtime + + + + + + + + io.helidon.logging:helidon-logging-jul:jar:4.0.6:runtime + + + + + + + + io.helidon.common:helidon-common-context:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.logging:helidon-logging-common:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common:jar:4.0.6:compile + + + + + + + compile + + + + + + + runtime + + + + + + + io.smallrye:jandex:jar:3.1.2:runtime + + + + + + + runtime + + + + + + + + jakarta.activation:jakarta.activation-api:jar:2.1.1:compile + + + + + + + compile + + + + + + + + org.eclipse.microprofile.metrics:microprofile-metrics-api:jar:5.0.1:compile + + + + + + + + jakarta.interceptor:jakarta.interceptor-api:jar:2.1.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.microprofile.metrics:helidon-microprofile-metrics:jar:4.0.6:compile + + + + + + + + io.helidon.webserver.observe:helidon-webserver-observe-metrics:jar:4.0.6:compile + + + + + + + + io.helidon.metrics.providers:helidon-metrics-providers-micrometer:jar:4.0.6:compile + + + + + + + + io.micrometer:micrometer-core:jar:1.11.3:compile + + + + + + + + io.micrometer:micrometer-commons:jar:1.11.3:compile + + + + + + + compile + + + + + + + + io.micrometer:micrometer-observation:jar:1.11.3:compile + + + + + + + compile + + + + + + + + org.hdrhistogram:HdrHistogram:jar:2.1.12:runtime + + + + + + + runtime + + + + + + + org.latencyutils:LatencyUtils:jar:2.0.3:runtime + + + + + + + runtime + + + + + + + compile + + + + + + + + io.micrometer:micrometer-registry-prometheus:jar:1.11.3:compile + + + + + + + + io.prometheus:simpleclient_common:jar:0.16.0:compile + + + + + + + io.prometheus:simpleclient:jar:0.16.0:compile + + + + + + + + io.prometheus:simpleclient_tracer_otel:jar:0.16.0:compile + + + + + + + compile + + + + + + + + io.prometheus:simpleclient_tracer_otel_agent:jar:0.16.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.prometheus:simpleclient_tracer_common:jar:0.16.0:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.metrics:helidon-metrics-api:jar:4.0.6:compile + + + + + + + io.helidon.http:helidon-http:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-configurable:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-buffers:jar:4.0.6:compile + + + + + + + compile + + + + + + + + io.helidon.common:helidon-common-uri:jar:4.0.6:compile + + + + + + + + io.helidon.common:helidon-common-parameters:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.builder:helidon-builder-api:jar:4.0.6:compile + + + + + + + compile + + + + + + + compile + + + + + + + + io.helidon.metrics:helidon-metrics-system-meters:jar:4.0.6:runtime + + + + + + + runtime + + + + + + + compile + + + + + + + + org.junit.jupiter:junit-jupiter-api:jar:5.9.3:test + + + + + + + org.opentest4j:opentest4j:jar:1.2.0:test + + + + + + + test + + + + + + + + org.junit.platform:junit-platform-commons:jar:1.9.3:test + + + + + + + test + + + + + + + org.apiguardian:apiguardian-api:jar:1.1.2:test + + + + + + + test + + + + + + + test + + + + + + + + io.helidon.microprofile.testing:helidon-microprofile-testing-junit5:jar:4.0.6:test + + + + + + + + io.helidon.jersey:helidon-jersey-client:jar:4.0.6:test + + + + + + + + org.glassfish.jersey.core:jersey-client:jar:3.1.5:compile + + + + + + + compile + + + + + + + + org.glassfish.jersey.inject:jersey-hk2:jar:3.1.5:compile + + + + + + + org.glassfish.hk2:hk2-locator:jar:3.0.5:compile + + + + + + + + org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.5:compile + + + + + + + compile + + + + + + + org.glassfish.hk2:hk2-api:jar:3.0.5:compile + + + + + + + compile + + + + + + + org.glassfish.hk2:hk2-utils:jar:3.0.5:compile + + + + + + + compile + + + + + + + compile + + + + + + + org.javassist:javassist:jar:3.29.2-GA:compile + + + + + + + compile + + + + + + + compile + + + + + + + test + + + + + + + + io.helidon.config:helidon-config-yaml-mp:jar:4.0.6:compile + + + + + + + compile + + + + + + + test + + + + + + + org.hamcrest:hamcrest-all:jar:1.3:test + + + + + + + test + + + + + + + org.projectlombok:lombok:jar:1.18.30:provided + + + + + + + provided + + + + + diff --git a/dependencyanalyser/testdata/pom.xml b/dependencyanalyser/testdata/pom.xml new file mode 100644 index 0000000..4419098 --- /dev/null +++ b/dependencyanalyser/testdata/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + com.oracle.timg.demo + dependencyanalyser + 0.0.1-SNAPSHOT + dependencyanalyser + analysies mvn output file looking for conflicting dependencies + + 1.18.32 + 2.37 + + + + + + + + + + + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + + + org.glassfish.jaxb + jaxb-runtime + runtime + 2.3.3 + + + + org.projectlombok + lombok + ${version.lombok} + provided + + + com.kazurayam + subprocessj + 0.3.7 + + + args4j + args4j + ${version.args4j} + + + \ No newline at end of file