ArtifactResolver.java

/*
 * Copyright 2017 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.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.maven.project.MavenProject;
import org.appformer.maven.support.AFReleaseId;
import org.appformer.maven.support.DependencyFilter;
import org.appformer.maven.support.MinimalPomParser;
import org.appformer.maven.support.PomModel;
import org.eclipse.aether.artifact.Artifact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.appformer.maven.integration.embedder.MavenProjectLoader.parseMavenPom;

public abstract class ArtifactResolver {

    private static final Logger log = LoggerFactory.getLogger(ArtifactResolver.class);

    public static ArtifactResolver getResolverFor(ClassLoader classLoader, AFReleaseId releaseId, boolean allowDefaultPom) {
        InJarArtifactResolver inJarResolver = new InJarArtifactResolver(classLoader, releaseId);
        if (inJarResolver.isLoaded()) {
            return inJarResolver;
        }

        ExplodedJarArtifactResolver explodedJarArtifactResolver = new ExplodedJarArtifactResolver(classLoader, releaseId);
        if (explodedJarArtifactResolver.isLoaded()) {
            return explodedJarArtifactResolver;
        }

        ArtifactResolver resolver = getResolverFor(releaseId, allowDefaultPom);
        if (resolver != null) {
            return resolver;
        }

        return null;
    }

    public static ArtifactResolver getResolverFor(AFReleaseId releaseId, boolean allowDefaultPom) {
        File pomFile = getPomFileForGAV( releaseId, allowDefaultPom );
        if (pomFile != null) {
            ArtifactResolver artifactResolver = getResolverFor(pomFile);
            if (artifactResolver != null) {
                return artifactResolver;
            }
        }
        return allowDefaultPom ? new DefaultArtifactResolver() : null;
    }

    public static ArtifactResolver getResolverFor(URI uri) {
        return getResolverFor(new File(uri));
    }

    public static ArtifactResolver getResolverFor(File pomFile) {
        try {
            return new DefaultArtifactResolver(parseMavenPom(pomFile));
        } catch (RuntimeException e) {
            log.warn("Cannot use native maven pom parser, fall back to the internal one", e);
            PomParser pomParser = createInternalPomParser(pomFile);
            if (pomParser != null) {
                return new DefaultArtifactResolver(pomParser);
            }
        }
        return null;
    }

    public static ArtifactResolver getResolverFor(InputStream pomStream) {
        MavenProject mavenProject = parseMavenPom(pomStream);
        return new DefaultArtifactResolver(mavenProject);
    }

    private static File getPomFileForGAV(AFReleaseId releaseId, boolean allowDefaultPom) {
        String artifactName = releaseId.getGroupId() + ":" + releaseId.getArtifactId() + ":pom:" + releaseId.getVersion();
        Artifact artifact = MavenRepository.getMavenRepository().resolveArtifact(artifactName, !allowDefaultPom);
        return artifact != null ? artifact.getFile() : null;
    }

    public static ArtifactResolver getResolverFor(InputStream pomStream, AFReleaseId releaseId, boolean allowDefaultPom ) {
        if (pomStream != null) {
            ArtifactResolver artifactResolver = getResolverFor(pomStream);
            if (artifactResolver != null) {
                return artifactResolver;
            }
        }
        return getResolverFor(releaseId, allowDefaultPom);
    }

    public static ArtifactResolver getResolverFor(PomModel pomModel ) {
        return pomModel instanceof MavenPomModelGenerator.MavenModel ?
                new DefaultArtifactResolver(((MavenPomModelGenerator.MavenModel) pomModel).getMavenProject()) : new DefaultArtifactResolver();
    }

    private static InternalPomParser createInternalPomParser(File pomFile) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(pomFile);
            return new InternalPomParser(MinimalPomParser.parse(pomFile.getAbsolutePath(), fis));
        } catch (FileNotFoundException e) {
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("Cannot create internal pom parser", e);
                }
            }
        }
        return null;
    }

    private static class InternalPomParser implements PomParser {

        private final PomModel pomModel;

        private InternalPomParser(PomModel pomModel) {
            this.pomModel = pomModel;
        }

        @Override
        public List<DependencyDescriptor> getPomDirectDependencies(DependencyFilter filter) {
            List<DependencyDescriptor> deps = new ArrayList<DependencyDescriptor>();
            for (AFReleaseId rId : pomModel.getDependencies(filter)) {
                deps.add(new DependencyDescriptor(rId));
            }
            return deps;
        }
    }

    public static ArtifactResolver create() {
        return new DefaultArtifactResolver();
    }

    public Collection<DependencyDescriptor> getAllDependecies(DependencyFilter dependencyFilter) {
        Set<DependencyDescriptor> dependencies = new HashSet<DependencyDescriptor>();
        for (DependencyDescriptor dep : getPomDirectDependencies(dependencyFilter)) {
            dependencies.add(dep);
            for (DependencyDescriptor transitiveDep : getArtifactDependecies(dep.toString())) {
                if (dependencyFilter.accept(dep.getReleaseId(), dep.getScope())) {
                    dependencies.add(transitiveDep);
                }
            }
        }
        return dependencies;
    }

    public Collection<DependencyDescriptor> getAllDependecies() {
        return getAllDependecies((releaseId, scope) -> true);
    }

    public abstract List<DependencyDescriptor> getPomDirectDependencies(DependencyFilter dependencyFilter);



    public abstract Artifact resolveArtifact(AFReleaseId releaseId);

    public abstract List<DependencyDescriptor> getArtifactDependecies(String artifactName);

    public static class ArtifactLocation {

        private boolean classPath;
        private URL url;
        private Artifact artifact;

        public ArtifactLocation(Artifact artifact, URL url, boolean classPath) {
            this.url = url;
            this.artifact = artifact;
            this.classPath = classPath;
        }

        public Artifact getArtifact() {
            return artifact;
        }


        public URL toURL() {
            return url;
        }

        public boolean isClassPath() {
            return classPath;
        }

    }

    public abstract ArtifactLocation resolveArtifactLocation(AFReleaseId releaseId);
}