AbstractFilesArtifactResolver.java
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.appformer.maven.integration;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.DefaultModelReader;
import org.appformer.maven.support.AFReleaseId;
import org.appformer.maven.support.AFReleaseIdImpl;
import org.appformer.maven.support.DependencyFilter;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;
public abstract class AbstractFilesArtifactResolver extends ArtifactResolver {
private static final Logger log = LoggerFactory.getLogger(AbstractFilesArtifactResolver.class);
private final AFReleaseId releaseId;
private ClassLoader classLoader;
private List<URL> jarRepository;
private List<URL> effectivePoms;
private PomParser pomParser;
AbstractFilesArtifactResolver(ClassLoader classLoader, AFReleaseId releaseId) {
this.classLoader = classLoader;
this.jarRepository = new ArrayList<>();
this.effectivePoms = new ArrayList<>();
this.releaseId = releaseId;
init();
}
public boolean isLoaded() {
return pomParser != null;
}
// initialize in jar repository
protected void init() {
jarRepository = buildResources(name -> isInJarStructuredFolder(name, "jar"));
effectivePoms = buildResources(name -> isInJarStructuredFolder(name, "pom"));
pomParser = buildPomParser(releaseId);
}
protected abstract List<URL> buildResources(Predicate<String> predicate);
protected abstract URL getURL(String path);
public ClassLoader getClassLoader() {
return classLoader;
}
public List<URL> getJarRepository() {
return jarRepository;
}
public PomParser getPomParser() {
return pomParser;
}
public List<URL> getEffectivePoms() {
return effectivePoms;
}
private boolean isInJarStructuredFolder(String name, String type) {
String[] paths = new String[]{"BOOT-INF/classes/KIE-INF/", "KIE-INF/lib/"};
for (String path : paths) {
// a bit of a hack "contains call"
if (name.contains(path) && name.endsWith("." + type)) {
return true;
}
}
return false;
}
private PomParser buildPomParser(AFReleaseId releaseId) {
final String pomName = toFile(releaseId, "pom");
List<URL> url = effectivePoms.stream().filter(e -> e.getFile().endsWith(pomName)).collect(toList());
if (url.isEmpty() && releaseId.getVersion().endsWith("-SNAPSHOT")) {
url = effectivePoms.stream().filter(e -> {
return Pattern.compile(toFileSnapshotRegex(releaseId, "pom")).matcher(e.getFile()).find();
}).collect(toList());
}
if (url.isEmpty()) {
return null;
}
String path = url.get(0).toExternalForm();
URL pomFile = getURL(path);
if (pomFile == null) {
log.warn("Maven pom not found in path {}", path);
return null;
}
try (InputStream pomStream = pomFile.openStream()) {
DefaultModelReader reader = new DefaultModelReader();
Model model = reader.read(pomStream, Collections.emptyMap());
// dependencies were resolved already creating the effective pom during kjar creation
return filter -> {
List<DependencyDescriptor> deps = new ArrayList<>();
for (Dependency dep : model.getDependencies()) {
DependencyDescriptor depDescr = new DependencyDescriptor(dep);
if (depDescr.isValid() && filter.accept(depDescr.getReleaseId(), depDescr.getScope())) {
deps.add(depDescr);
}
}
return deps;
};
} catch (Exception e) {
log.error("Could not read pom in jar {}", pomFile);
return null;
}
}
@Override
public ArtifactLocation resolveArtifactLocation(AFReleaseId releaseId) {
log.debug("resolve location {}", releaseId);
Optional<URL> url = tryInStructuredJar(releaseId);
if (url.isPresent()) {
DefaultArtifact artifact = new DefaultArtifact(releaseId.toExternalForm());
return new ArtifactLocation(artifact.setFile(new File(url.get().toString())), url.get(), true);
}
return null;
}
@Override
public Artifact resolveArtifact(AFReleaseId releaseId) {
Optional<URL> url = tryInStructuredJar(releaseId);
if (url.isPresent()) {
log.info("Resolved in jar repository {}", url);
DefaultArtifact artifact = new DefaultArtifact(releaseId.toExternalForm());
return artifact.setFile(new File(url.get().toString()));
}
return null;
}
protected Optional<URL> tryInStructuredJar(String artifactName) {
for (URL inJarURL : jarRepository) {
if (inJarURL.getFile().endsWith(artifactName)) {
return Optional.of(inJarURL);
}
}
return Optional.empty();
}
protected Optional<URL> tryInStructuredJar(AFReleaseId releaseId) {
return tryInStructuredJar(toFile(releaseId, "jar"));
}
private String toFile(AFReleaseId releaseId, String type) {
return releaseId.getArtifactId() + "-" + releaseId.getVersion() + "." + type;
}
private String toFileSnapshotRegex(AFReleaseId releaseId, String type) {
return releaseId.getArtifactId() + "-" + releaseId.getVersion().replace("-SNAPSHOT", ".*") + "." + type + "$";
}
@Override
public List<DependencyDescriptor> getArtifactDependecies(String artifactName) {
AFReleaseId releaseId = new AFReleaseIdImpl(artifactName);
PomParser builtPomParser = buildPomParser(releaseId);
return builtPomParser != null ? builtPomParser.getPomDirectDependencies(DependencyFilter.COMPILE_FILTER) : emptyList();
}
@Override
public List<DependencyDescriptor> getPomDirectDependencies(DependencyFilter dependencyFilter) {
return (pomParser != null) ? pomParser.getPomDirectDependencies(dependencyFilter) : emptyList();
}
}