Skip to content

Instantly share code, notes, and snippets.

@basilevs
Created January 14, 2026 12:13
Show Gist options
  • Select an option

  • Save basilevs/eabbfbbc4a141d87d1062268c7cc24b1 to your computer and use it in GitHub Desktop.

Select an option

Save basilevs/eabbfbbc4a141d87d1062268c7cc24b1 to your computer and use it in GitHub Desktop.
A script to get an URL of Maven artifact in a remote repository. Naive implementation.
/*******************************************************************************
* Copyright (c) 2025 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package com.example;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class ResolveMavenArtifact {
private URI repository= URI.create("https://repo.eclipse.org/content/repositories/rcptt-snapshots/");
private String artifactId="agent-server-products", groupId="org.eclipse.rcptt.cloud", version, classifier="", extension="zip";
private enum Parameter {
REPOSITORY {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.repository = URI.create(commandLine.next());
}
},
GROUPID {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.groupId = consumeIdentifier(commandLine);
}
},
ARTIFACTID {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.artifactId = consumeIdentifier(commandLine);
}
},
VERSION {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.version = consumeIdentifier(commandLine);
}
},
CLASSIFIER {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.classifier = consumeIdentifier(commandLine);
}
},
EXTENSION {
@Override
void process(ResolveMavenArtifact configuration, Iterator<String> commandLine) {
configuration.extension = consumeIdentifier(commandLine);
}
};
boolean matches(String argument) {
return argument.contentEquals("--" + name().toLowerCase())
|| argument.equals("-" + name().substring(0, 1).toLowerCase());
}
abstract void process(ResolveMavenArtifact configuration, Iterator<String> commandLine);
}
public void parseCommandLine(Iterator<String> command) {
while (command.hasNext()) {
Parameter parameter = toParameter(command.next());
try {
parameter.process(this, command);
} catch (RuntimeException e) {
throw new IllegalArgumentException("Failed to process parameter " + parameter, e);
}
}
}
public static void main(String[] args) throws IOException {
ResolveMavenArtifact resolve = new ResolveMavenArtifact();
resolve.parseCommandLine(Arrays.asList(args).iterator());
URI result = resolve.resolveArtifact();
System.out.println(result);
}
private URI resolveArtifact() throws IOException {
requireNonNull(artifactId, "artifactId");
requireNonNull(version, "version");
URI directory = repository.resolve(groupId.replace('.', '/')+"/").resolve(artifactId+"/").resolve(version+"/");
String resolvedVersion = version;
if (version.endsWith("-SNAPSHOT")) {
final URL url = directory.resolve("maven-metadata.xml").toURL();
try (var is = url.openStream()) {
resolvedVersion = version.substring(0, version.length() - 8) + parseLatestSnapshot(is);
} catch (SAXException e) {
throw new IOException(e);
}
}
String filename = artifactId + "-" + resolvedVersion + (classifier.isEmpty() ? "" : "-"+classifier) + "." + extension;
return directory.resolve(filename);
}
public static String parseLatestSnapshot(InputStream input) throws IOException, SAXException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(input);
Node snapshotNode = xpathNode(document, "/metadata/versioning/snapshot");
return Stream.of("timestamp", "buildNumber").map(p -> xpathNode(snapshotNode, p)).map(Node::getTextContent)
.collect(Collectors.joining("-"));
} catch (ParserConfigurationException e) {
throw new AssertionError(e);
}
}
private static Node xpathNode(Node origin, String expression) {
XPath xpath = XPathFactory.newInstance().newXPath();
try {
return (Node) xpath.evaluate(expression, origin, XPathConstants.NODE);
} catch (XPathExpressionException e) {
throw new IllegalArgumentException(e);
}
}
private static String consumeIdentifier(Iterator<String> commandLine) {
return commandLine.next();
}
private static Parameter toParameter(String argument) {
var matching = Arrays.stream(Parameter.values()).filter(p -> p.matches(argument)).toList();
if (matching.size() != 1) {
throw new IllegalArgumentException(
"Argument " + argument + " is ambigious. It matches parameters: " + matching);
}
return matching.getFirst();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment