io.tesla.aether.internal.DefaultTeslaAether.java Source code

Java tutorial

Introduction

Here is the source code for io.tesla.aether.internal.DefaultTeslaAether.java

Source

/**
 * Copyright (c) 2012 to original author or authors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package io.tesla.aether.internal;

import com.google.common.collect.Lists;
import io.tesla.aether.Repository;
import io.tesla.aether.TeslaAether;
import io.tesla.aether.Workspace;
import io.tesla.aether.connector.AetherRepositoryConnectorFactory;
import io.tesla.aether.guice.DefaultModelCache;
import io.tesla.aether.guice.DefaultModelResolver;
import io.tesla.aether.guice.RepositorySystemSessionProvider;
import io.tesla.aether.guice.maven.MavenBehaviourRepositoryProvider;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.maven.model.Model;
import org.apache.maven.model.building.DefaultModelBuilderFactory;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuilder;
import org.apache.maven.model.building.ModelBuildingException;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.ArtifactType;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.connector.file.FileRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.Exclusion;
import org.eclipse.aether.impl.ArtifactResolver;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.internal.impl.DefaultFileProcessor;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.io.FileProcessor;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.filter.DependencyFilterUtils;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.eclipse.aether.version.Version;
import org.eclipse.sisu.Nullable;

import com.google.common.collect.ImmutableList;

@Named
public class DefaultTeslaAether implements TeslaAether {

    //private Logger logger = LoggerFactory.getLogger(TeslaAether.class);

    private RepositorySystem system;
    private RepositorySystemSession session;
    private ModelBuilder modelBuilder;
    private ArtifactResolver artifactResolver;
    private RemoteRepositoryManager remoteRepositoryManager;
    private List<RemoteRepository> remoteRepositories;

    public DefaultTeslaAether() {
        this(new File(System.getProperty("user.home"), ".m2/repository"), "http://repo1.maven.org/maven2/");
    }

    public DefaultTeslaAether(String localRepository, List<String> remoteRepositoryUris) {
        List<Repository> repositories = new ArrayList<Repository>();
        for (String remoteRepositoryUri : remoteRepositoryUris) {
            repositories.add(authenticatedRepositoryFromUri(remoteRepositoryUri));
        }
        init(new File(localRepository), repositories);
    }

    public DefaultTeslaAether(String localRepository, Repository... remoteRepositories) {
        init(new File(localRepository), Lists.newArrayList(remoteRepositories));
    }

    public DefaultTeslaAether(File localRepository, String... remoteRepositoryUris) {
        List<Repository> repositories = new ArrayList<Repository>();
        for (String remoteRepositoryUri : remoteRepositoryUris) {
            repositories.add(authenticatedRepositoryFromUri(remoteRepositoryUri));
        }
        init(localRepository, repositories);
    }

    private static Repository authenticatedRepositoryFromUri(String remoteRepositoryUri) {
        Repository repository = new Repository(remoteRepositoryUri);
        try {
            String userInfo = new URI(remoteRepositoryUri).getUserInfo();
            if (userInfo != null) {
                String[] auth = userInfo.split(":", 2);
                if (auth.length == 2) {
                    repository.setUsername(auth[0]);
                    repository.setPassword(auth[1]);
                } else {
                    // we should log a warning for invalid user info format here
                }
            }
        } catch (URISyntaxException e) {
            // we should log a warning here instead
            e.printStackTrace();
        }
        return repository;
    }

    public DefaultTeslaAether(List<RemoteRepository> remoteRepositories,
            RepositorySystemSession repositorySystemSession) {
        DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
        locator.addService(RepositoryConnectorFactory.class, FileRepositoryConnectorFactory.class);
        locator.addService(RepositoryConnectorFactory.class, AetherRepositoryConnectorFactory.class);
        locator.addService(FileProcessor.class, DefaultFileProcessor.class);

        this.system = locator.getService(RepositorySystem.class);
        this.session = repositorySystemSession;
        this.modelBuilder = new DefaultModelBuilderFactory().newInstance();
        this.artifactResolver = locator.getService(ArtifactResolver.class);
        this.remoteRepositoryManager = locator.getService(RemoteRepositoryManager.class);
        this.remoteRepositories = remoteRepositories;
    }

    private void init(File localRepository, List<Repository> repositories) {
        remoteRepositories = new ArrayList<RemoteRepository>();
        for (Repository r : repositories) {
            RemoteRepository.Builder builder = new RemoteRepository.Builder(r.getId(), "default", r.getUrl());
            if (r.getUsername() != null && r.getPassword() != null) {
                Authentication auth = new AuthenticationBuilder().addUsername(r.getUsername())
                        .addPassword(r.getPassword()).build();
                builder.setAuthentication(auth);
            }
            this.remoteRepositories.add(builder.build());
        }

        DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
        locator.addService(RepositoryConnectorFactory.class, FileRepositoryConnectorFactory.class);
        locator.addService(RepositoryConnectorFactory.class, AetherRepositoryConnectorFactory.class);
        locator.addService(FileProcessor.class, DefaultFileProcessor.class);

        this.system = locator.getService(RepositorySystem.class);
        this.session = new RepositorySystemSessionProvider(localRepository).get();
        this.modelBuilder = new DefaultModelBuilderFactory().newInstance();
        this.artifactResolver = locator.getService(ArtifactResolver.class);
        this.remoteRepositoryManager = locator.getService(RemoteRepositoryManager.class);
    }

    @Inject
    public DefaultTeslaAether(RepositorySystem system, RepositorySystemSession session, ModelBuilder modelBuilder,
            ArtifactResolver artifactResolver, RemoteRepositoryManager remoteRepositoryManager,
            @Nullable RemoteRepository remoteRepository) {
        this.system = system;
        this.session = session;
        this.modelBuilder = modelBuilder;
        this.artifactResolver = artifactResolver;
        this.remoteRepositoryManager = remoteRepositoryManager;

        // A bunch of defensive hacking to make an initial integration with Maven. Far from perfect

        // After a bunch of POM parsing the MavenProject ends up with a list of remote repositories, there's no decent way to really get at this
        // without passing it in as a parameter which I'm trying to avoid.
        if (remoteRepository == null) {

            this.remoteRepositories = ImmutableList.of(new MavenBehaviourRepositoryProvider().get());

            /*
             * String teslaAetherRemoteRepositories = System.getProperty(TeslaAether.REMOTE_REPOSITORY); if(teslaAetherRemoteRepositories == null) { throw new
             * RuntimeException("There are no remote repositories specified in the " + TeslaAether.REMOTE_REPOSITORY + " property."); }
             * 
             * String[] remoteRepos = StringUtils.split(teslaAetherRemoteRepositories, ","); for (String remoteRepositoryUri : remoteRepos) { remoteRepositories.add(getRemoteRepository(new
             * Repository(remoteRepositoryUri))); }
             */
        } else {
            this.remoteRepositories = ImmutableList.of(remoteRepository);
        }

        // Another hack because the MavenRepositoryUtils.newSession() doesn't really setup a useful session because there is no
        // repository manager
        if (session.getLocalRepositoryManager() == null) {
            LocalRepository localRepo = new LocalRepository(
                    new File(System.getProperty("user.home"), ".m2/repository"));
            //
            // We are not concerned with checking the _remote.repositories files
            //
            try {
                ((DefaultRepositorySystemSession) session).setLocalRepositoryManager(
                        new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
            } catch (NoLocalRepositoryManagerException e) {
                //
                // This should never happen
                //
            }

        }

    }

    // Model

    public Model resolveModel(File pom) throws ModelBuildingException {

        RequestTrace trace = new RequestTrace(pom);
        ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
        modelRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
        modelRequest.setProcessPlugins(false);
        modelRequest.setTwoPhaseBuilding(false);
        modelRequest.setSystemProperties(toProperties(session.getUserProperties(), session.getSystemProperties()));
        //
        // The model cache and default model resolver should be injected
        //
        modelRequest.setModelCache(new DefaultModelCache());
        modelRequest.setModelResolver(new DefaultModelResolver(session, trace.newChild(modelRequest), "bithub",
                artifactResolver, remoteRepositoryManager, remoteRepositories));
        modelRequest.setPomFile(pom);
        return modelBuilder.build(modelRequest).getEffectiveModel();
    }

    // <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
    public Model resolveModel(String coordinate) throws ModelBuildingException, ArtifactResolutionException {
        File pom = resolveArtifact(coordinate).getArtifact().getFile();
        return resolveModel(pom);
    }

    // Resolve single artifact

    public ArtifactResult resolveArtifact(String coordinate) throws ArtifactResolutionException {
        Artifact artifact = new DefaultArtifact(coordinate);
        return resolveArtifact(artifact);
    }

    public ArtifactResult resolveArtifact(Artifact artifact) throws ArtifactResolutionException {
        ArtifactRequest artifactRequest = new ArtifactRequest();
        artifactRequest.setArtifact(artifact);
        for (RemoteRepository remoteRepository : remoteRepositories) {
            artifactRequest.addRepository(remoteRepository);
        }
        return system.resolveArtifact(session, artifactRequest);
    }

    // Resolve transitive hulls

    public List<Artifact> resolveArtifacts(String coordinate) throws DependencyResolutionException {
        return resolveArtifacts(new DefaultArtifact(coordinate));
    }

    public List<Artifact> resolveArtifacts(Artifact artifact) throws DependencyResolutionException {
        DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
        CollectRequest collectRequest = new CollectRequest();
        collectRequest.setRoot(new Dependency(artifact, JavaScopes.RUNTIME));
        for (RemoteRepository remoteRepository : remoteRepositories) {
            collectRequest.addRepository(remoteRepository);
        }
        DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFlter);
        return resolveArtifacts(dependencyRequest);
    }

    public List<Artifact> resolveArtifacts(DependencyRequest request) throws DependencyResolutionException {
        //
        // We are attempting to encapsulate everything about resolution with this library. The dependency request requires
        // the collect request to have repositories set but this is all injected within this component so we have to set them.
        //
        CollectRequest collectRequest = request.getCollectRequest();
        if (collectRequest.getRepositories() == null || collectRequest.getRepositories().isEmpty()) {
            for (RemoteRepository remoteRepository : remoteRepositories) {
                collectRequest.addRepository(remoteRepository);
            }
        }

        DependencyResult result = system.resolveDependencies(session, request);

        List<Artifact> artifacts = new ArrayList<Artifact>();
        for (ArtifactResult ar : result.getArtifactResults()) {
            artifacts.add(ar.getArtifact());
        }
        return artifacts;
    }

    //
    // Workspace related
    //

    // There are two modes of reading a pom.xml. 
    //
    // - Reading the pom.xml where we are just trying to extract the coordinates of a release project to resolve released things
    // - Reading the pom.xml where we are working with something in process and we resolve the dependencies but not the artifact for the pom itself
    //
    // Here we really want to read the POM and resolve all the dependencies in the POM
    //
    public List<Artifact> resolveArtifacts(File modelFile)
            throws ModelBuildingException, DependencyResolutionException {
        Model model = resolveModel(modelFile);
        Artifact artifact = new DefaultArtifact(model.getGroupId(), model.getArtifactId(), model.getPackaging(),
                model.getVersion());
        return resolveArtifacts(artifact);
    }

    private Dependency toAetherDependency(org.apache.maven.model.Dependency dependency) {
        Artifact artifact = new DefaultArtifact(dependency.getGroupId(), dependency.getArtifactId(),
                dependency.getClassifier(), dependency.getType(), dependency.getVersion());
        ImmutableList.Builder<Exclusion> exclusions = ImmutableList.builder();
        for (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) {
            exclusions.add(new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), null, "*"));
        }
        return new Dependency(artifact, dependency.getScope(), dependency.isOptional(), exclusions.build());
    }

    public ArtifactType getArtifactType(String typeId) {
        return session.getArtifactTypeRegistry().get(typeId);
    }

    // Util

    private Properties toProperties(Map<String, String> dominant, Map<String, String> recessive) {
        Properties props = new Properties();
        if (recessive != null) {
            props.putAll(recessive);
        }
        if (dominant != null) {
            props.putAll(dominant);
        }
        return props;
    }

    public List<String> findAllVersions(String gaVersionRange) throws VersionRangeResolutionException {

        //    Artifact artifact = new DefaultArtifact( "org.codehaus.redback:redback-struts2-integration:[0,1.2.4)" );
        //
        //    RemoteRepository repo = Booter.newCentralRepository();
        //
        //    VersionRangeRequest rangeRequest = new VersionRangeRequest();
        //    rangeRequest.setArtifact( artifact );
        //    rangeRequest.addRepository( repo );
        //
        //    VersionRangeResult rangeResult = system.resolveVersionRange( session, rangeRequest );
        //
        //    List<Version> versions = rangeResult.getVersions();    

        Artifact artifact = new DefaultArtifact(gaVersionRange);
        VersionRangeRequest rangeRequest = new VersionRangeRequest();
        rangeRequest.setArtifact(artifact);
        for (RemoteRepository remoteRepository : remoteRepositories) {
            rangeRequest.addRepository(remoteRepository);
        }

        VersionRangeResult rangeResult = system.resolveVersionRange(session, rangeRequest);
        List<Version> versions = rangeResult.getVersions();
        List<String> result = new ArrayList<String>();
        for (Version v : versions) {
            result.add(v.toString());
        }
        return result;
    }

    public List<File> resolveWorkspace(Workspace workspace)
            throws ModelBuildingException, DependencyResolutionException {
        List<File> classpath = new ArrayList<File>();
        for (File projectDirectory : workspace.getProjectDirectories()) {
            //
            // Find the POM in each directory and resolve that
            //
            File pom = new File(projectDirectory, "pom.xml");
            Model model = resolveModel(pom);
            List<Artifact> artifacts = resolveArtifacts(new DefaultArtifact(model.getGroupId(),
                    model.getArtifactId(), model.getPackaging(), model.getVersion()));
            for (Artifact artifact : artifacts) {
                classpath.add(artifact.getFile());
            }
            //
            // We also want the ${build.directory}/classes directory
            //
            File classes = new File(model.getBuild().getDirectory(), "classes");
            classpath.add(classes);
        }
        return classpath;
    }
}