2022-09-06 11:15:21 +02:00
|
|
|
package io.gitlab.jfronny.inceptum.common.api;
|
|
|
|
|
|
|
|
import io.gitlab.jfronny.commons.HttpUtils;
|
|
|
|
import io.gitlab.jfronny.inceptum.common.*;
|
|
|
|
import io.gitlab.jfronny.inceptum.common.model.maven.MavenDependency;
|
|
|
|
import io.gitlab.jfronny.inceptum.common.model.maven.Pom;
|
|
|
|
import org.w3c.dom.*;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
|
|
|
|
import javax.xml.parsers.*;
|
|
|
|
import javax.xml.stream.XMLStreamException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.net.URISyntaxException;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
public class MavenApi {
|
|
|
|
private static final DocumentBuilder FACTORY;
|
|
|
|
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
FACTORY = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
|
|
|
} catch (ParserConfigurationException e) {
|
|
|
|
throw new RuntimeException("Could not create document builder", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Path downloadLibrary(String repo, String artifact) throws IOException, URISyntaxException {
|
|
|
|
String path = mavenNotationToJarPath(artifact);
|
|
|
|
Path res = MetaHolder.LIBRARIES_DIR.resolve(path);
|
|
|
|
Net.downloadFile(Utils.join("/", repo, path), res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Pom getPom(String repo, String artifact) throws IOException, SAXException, URISyntaxException, XMLStreamException {
|
|
|
|
try (InputStream is = HttpUtils.get(Utils.join("/", repo, mavenNotationToPomPath(artifact))).sendInputStream()) {
|
|
|
|
Document doc = FACTORY.parse(is);
|
|
|
|
doc.getDocumentElement().normalize();
|
|
|
|
Pom result = new Pom();
|
|
|
|
if (!"project".equals(doc.getDocumentElement().getNodeName())) throw new IOException("Illegal document name");
|
|
|
|
boolean hasModelVersion = false;
|
|
|
|
boolean hasGroupId = false;
|
|
|
|
boolean hasArtifactId = false;
|
|
|
|
boolean hasVersion = false;
|
|
|
|
for (Node node : iterable(doc.getDocumentElement().getChildNodes())) {
|
2022-09-06 12:35:29 +02:00
|
|
|
if (isWhitespace(node)) continue;
|
2022-09-06 11:15:21 +02:00
|
|
|
switch (node.getNodeName()) {
|
|
|
|
case "modelVersion" -> {
|
|
|
|
hasModelVersion = true;
|
|
|
|
result.modelVersion = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "groupId" -> {
|
|
|
|
hasGroupId = true;
|
|
|
|
result.groupId = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "artifactId" -> {
|
|
|
|
hasArtifactId = true;
|
|
|
|
result.artifactId = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "version" -> {
|
|
|
|
hasVersion = true;
|
|
|
|
result.version = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "packaging" -> result.packaging = node.getTextContent();
|
|
|
|
case "dependencies" -> {
|
|
|
|
result.dependencies = new LinkedList<>();
|
|
|
|
for (Node dep : iterable(node.getChildNodes())) {
|
2022-09-06 12:35:29 +02:00
|
|
|
if (isWhitespace(dep)) continue;
|
2022-09-06 11:15:21 +02:00
|
|
|
result.dependencies.add(parseDependency(dep));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default -> {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hasModelVersion) throw new IOException("Pom lacks modelVersion");
|
|
|
|
if (!hasGroupId) throw new IOException("Pom lacks groupId");
|
|
|
|
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
|
|
|
|
if (!hasVersion) throw new IOException("Pom lacks version");
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-06 12:35:29 +02:00
|
|
|
private static boolean isWhitespace(Node node) {
|
|
|
|
return node.getNodeType() == Node.TEXT_NODE && node.getTextContent().isBlank();
|
|
|
|
}
|
|
|
|
|
2022-09-06 11:15:21 +02:00
|
|
|
private static MavenDependency parseDependency(Node doc) throws IOException {
|
|
|
|
MavenDependency result = new MavenDependency();
|
|
|
|
boolean hasGroupId = false;
|
|
|
|
boolean hasArtifactId = false;
|
|
|
|
boolean hasVersion = false;
|
|
|
|
boolean hasScope = false;
|
|
|
|
for (Node node : iterable(doc.getChildNodes())) {
|
2022-09-06 12:35:29 +02:00
|
|
|
if (isWhitespace(node)) continue;
|
2022-09-06 11:15:21 +02:00
|
|
|
switch (node.getNodeName()) {
|
|
|
|
case "groupId" -> {
|
|
|
|
hasGroupId = true;
|
|
|
|
result.groupId = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "artifactId" -> {
|
|
|
|
hasArtifactId = true;
|
|
|
|
result.artifactId = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "version" -> {
|
|
|
|
hasVersion = true;
|
|
|
|
result.version = node.getTextContent();
|
|
|
|
}
|
|
|
|
case "scope" -> {
|
|
|
|
hasScope = true;
|
|
|
|
result.scope = node.getTextContent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!hasGroupId) throw new IOException("Pom lacks groupId");
|
|
|
|
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
|
|
|
|
if (!hasVersion) throw new IOException("Pom lacks version");
|
|
|
|
if (!hasScope) throw new IOException("Pom lacks scope");
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Iterable<Node> iterable(NodeList list) {
|
|
|
|
return () -> new Iterator<>() {
|
|
|
|
int index = 0;
|
|
|
|
@Override
|
|
|
|
public boolean hasNext() {
|
|
|
|
return index < list.getLength() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Node next() {
|
|
|
|
if (!hasNext()) throw new NoSuchElementException();
|
|
|
|
return list.item(index++);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts an artifact in maven notation to a jar file path. The following are supported:
|
|
|
|
* - some.base.path:artifact:version -> some/base/path/artifact/version/artifact-version.jar
|
|
|
|
* - some.base.path:artifact:version:classifier -> some/base/path/artifact/version/artifact-version-classifier.jar
|
|
|
|
* @param mavenNotation An artifact in maven notation
|
|
|
|
* @return A file path
|
|
|
|
*/
|
|
|
|
public static String mavenNotationToJarPath(String mavenNotation) {
|
|
|
|
if (Objects.requireNonNull(mavenNotation).isEmpty()) throw new IllegalArgumentException("The notation is empty");
|
|
|
|
String[] lib = mavenNotation.split(":");
|
|
|
|
if (lib.length <= 1) throw new IllegalArgumentException("Not in maven notation");
|
|
|
|
if (lib.length == 2) throw new IllegalArgumentException("Skipping versions is not supported");
|
|
|
|
if (lib.length >= 5) throw new IllegalArgumentException("Unkown elements in maven notation");
|
|
|
|
String path = lib[0].replace('.', '/') + '/'; // Base
|
|
|
|
path += lib[1] + '/'; // Artifact name
|
|
|
|
path += lib[2] + '/'; // Version
|
|
|
|
if (lib.length == 3) { // artifact-version.jar
|
|
|
|
path += lib[1] + '-' + lib[2];
|
|
|
|
} else { // artifact-version-classifier.jar
|
|
|
|
path += lib[1] + '-' + lib[2] + "-" + lib[3];
|
|
|
|
}
|
|
|
|
return path + ".jar";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts an artifact in maven notation to a pom file path. The following are supported:
|
|
|
|
* - some.base.path:artifact:version -> some/base/path/artifact/version/artifact-version.pom
|
|
|
|
* - some.base.path:artifact:version:classifier -> some/base/path/artifact/version/artifact-version.pom
|
|
|
|
* @param mavenNotation An artifact in maven notation
|
|
|
|
* @return A file path
|
|
|
|
*/
|
|
|
|
public static String mavenNotationToPomPath(String mavenNotation) {
|
|
|
|
if (Objects.requireNonNull(mavenNotation).isEmpty()) throw new IllegalArgumentException("The notation is empty");
|
|
|
|
String[] lib = mavenNotation.split(":");
|
|
|
|
if (lib.length <= 1) throw new IllegalArgumentException("Not in maven notation");
|
|
|
|
if (lib.length == 2) throw new IllegalArgumentException("Skipping versions is not supported");
|
|
|
|
if (lib.length >= 5) throw new IllegalArgumentException("Unkown elements in maven notation");
|
|
|
|
String path = lib[0].replace('.', '/') + '/'; // Base
|
|
|
|
path += lib[1] + '/'; // Artifact name
|
|
|
|
path += lib[2] + '/'; // Version
|
2022-09-06 12:35:29 +02:00
|
|
|
path += lib[1] + '-' + lib[2]; // artifact-version
|
2022-09-06 11:15:21 +02:00
|
|
|
return path + ".pom";
|
|
|
|
}
|
|
|
|
}
|