com.runwaysdk.business.generation.maven.MavenClasspathBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.runwaysdk.business.generation.maven.MavenClasspathBuilder.java

Source

/**
 * Copyright (c) 2013 TerraFrame, Inc. All rights reserved. 
 *   
 * This file is part of Runway SDK(tm).
 * 
 * Runway SDK(tm) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * Runway SDK(tm) is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with Runway SDK(tm).  If not, see <http://www.gnu.org/licenses/>.
 */

package com.runwaysdk.business.generation.maven;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Repository;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.internal.DefaultServiceLocator;
import org.apache.maven.repository.internal.MavenRepositorySystemSession;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.providers.http.HttpWagon;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.collection.CollectRequest;
import org.sonatype.aether.connector.file.FileRepositoryConnectorFactory;
import org.sonatype.aether.connector.wagon.WagonProvider;
import org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory;
import org.sonatype.aether.graph.Dependency;
import org.sonatype.aether.graph.DependencyFilter;
import org.sonatype.aether.repository.LocalRepository;
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.resolution.ArtifactResult;
import org.sonatype.aether.resolution.DependencyRequest;
import org.sonatype.aether.resolution.DependencyResolutionException;
import org.sonatype.aether.spi.connector.RepositoryConnectorFactory;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.artifact.JavaScopes;
import org.sonatype.aether.util.filter.DependencyFilterUtils;

import com.runwaysdk.dataaccess.CoreException;

public class MavenClasspathBuilder {
    private static Log log = LogFactory.getLog(MavenClasspathBuilder.class);

    public static void main(String[] args) throws Exception {
        List<String> classpath = getClasspathFromMavenProject(
                new File("/users/terraframe/documents/workspace2/TestProj/pom.xml"),
                new File("/users/terraframe/.m2/repository"), false);
        System.out.println("classpath = " + classpath);
    }

    public static List<String> getClasspathFromMavenProject(File projectPom, File localRepoFolder,
            boolean isRunwayEnvironment) throws DependencyResolutionException, IOException, XmlPullParserException {
        MavenProject proj = loadProject(projectPom);

        PropertyReplacer propReplacer = new PropertyReplacer(proj);

        List<Repository> repos = proj.getRepositories();

        List<String> classpath = new ArrayList<String>();

        RepositorySystem system = Booter.newRepositorySystem();
        RepositorySystemSession session = Booter.newRepositorySystemSession(system, localRepoFolder);
        RemoteRepository centralRepo = Booter.newCentralRepository();
        DependencyFilter classpathFlter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);

        List<org.apache.maven.model.Dependency> dependencies = proj.getDependencies();
        Iterator<org.apache.maven.model.Dependency> it = dependencies.iterator();

        while (it.hasNext()) {
            org.apache.maven.model.Dependency depend = it.next();

            Artifact artifact = new DefaultArtifact(propReplacer.replace(depend.getGroupId()),
                    propReplacer.replace(depend.getArtifactId()), propReplacer.replace(depend.getClassifier()),
                    propReplacer.replace(depend.getType()), propReplacer.replace(depend.getVersion()));

            CollectRequest collectRequest = new CollectRequest();
            collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE));
            collectRequest.addRepository(centralRepo);

            for (Repository repo : repos) {
                collectRequest.addRepository(new RemoteRepository(propReplacer.replace(repo.getId()),
                        propReplacer.replace(repo.getLayout()), propReplacer.replace(repo.getUrl())));
            }

            try {
                DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFlter);

                List<ArtifactResult> artifactResults = system.resolveDependencies(session, dependencyRequest)
                        .getArtifactResults();

                for (ArtifactResult artifactResult : artifactResults) {
                    Artifact art = artifactResult.getArtifact();

                    if (isRunwayEnvironment && art.getGroupId().equals("com.runwaysdk")
                            && (art.getArtifactId().equals("runwaysdk-client")
                                    || art.getArtifactId().equals("runwaysdk-common")
                                    || art.getArtifactId().equals("runwaysdk-server"))) {
                        continue;
                    }

                    classpath.add(art.getFile().getAbsolutePath());
                }
            } catch (DependencyResolutionException e) {
                // Is Maven ignoring this? I'm confused.
                log.error(e);
                e.printStackTrace();
            }
        }

        if (log.isTraceEnabled()) {
            String cpath = "";
            for (Iterator<String> i = classpath.iterator(); i.hasNext();) {
                cpath = cpath + ", " + i.next();
            }

            log.trace("Resolved pom [" + projectPom.getAbsolutePath() + "] classpath to [" + cpath + "]");
        }

        return classpath;
    }

    public static MavenProject loadProject(File pomFile) throws IOException, XmlPullParserException {
        MavenProject ret = null;
        MavenXpp3Reader mavenReader = new MavenXpp3Reader();

        if (pomFile != null && pomFile.exists()) {
            FileReader reader = null;

            try {
                reader = new FileReader(pomFile);
                Model model = mavenReader.read(reader);
                model.setPomFile(pomFile);

                List<Repository> repositories = model.getRepositories();
                Properties properties = model.getProperties();
                properties.setProperty("basedir", pomFile.getParent());

                Parent parent = model.getParent();
                if (parent != null) {
                    File parentPom = new File(pomFile.getParent(), parent.getRelativePath());
                    MavenProject parentProj = loadProject(parentPom);

                    if (parentProj == null) {
                        throw new CoreException("Unable to load parent project at " + parentPom.getAbsolutePath());
                    }

                    repositories.addAll(parentProj.getRepositories());
                    model.setRepositories(repositories);

                    properties.putAll(parentProj.getProperties());
                }

                ret = new MavenProject(model);
            } finally {
                reader.close();
            }
        }

        return ret;
    }

    private static class PropertyReplacer {
        Properties props;

        protected PropertyReplacer(MavenProject proj) {
            props = proj.getProperties();
        }

        private String replace(String input) {
            if (input == null) {
                return input;
            }

            int start = input.indexOf("${");
            int end = input.lastIndexOf("}");

            if (start != -1 && end != -1) {
                String key = input.substring(start + 2, end);

                if (props.containsKey(key)) {
                    return input.replace("${" + key + "}", this.replace(props.getProperty(key)));
                }
            }

            return input;
        }
    }

    /**
     * A helper to boot the repository system and a repository system session.
     * 
     * http://stackoverflow.com/questions/11799923/programmatically-resolving-maven-dependencies-outside-of-a-plugin-get-reposito/16906463#16906463
     */
    public static class Booter {
        public static RepositorySystem newRepositorySystem() {
            /*
             * Aether's components implement org.sonatype.aether.spi.locator.Service to ease manual wiring and using the
             * prepopulated DefaultServiceLocator, we only need to register the repository connector factories.
             */
            DefaultServiceLocator locator = new DefaultServiceLocator();
            locator.addService(RepositoryConnectorFactory.class, FileRepositoryConnectorFactory.class);
            locator.addService(RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class);
            locator.setServices(WagonProvider.class, new ManualWagonProvider());

            return locator.getService(RepositorySystem.class);
        }

        public static RepositorySystemSession newRepositorySystemSession(RepositorySystem system,
                File localRepoDir) {
            MavenRepositorySystemSession session = new MavenRepositorySystemSession();

            LocalRepository localRepo = new LocalRepository(localRepoDir);
            session.setLocalRepositoryManager(system.newLocalRepositoryManager(localRepo));

            session.setTransferListener(new TransferListener());
            session.setRepositoryListener(new RepositoryListener());

            return session;
        }

        public static RemoteRepository newCentralRepository() {
            return new RemoteRepository("central", "default", "http://repo1.maven.org/maven2/");
        }
    }

    /**
     * A simplistic provider for wagon instances when no Plexus-compatible IoC container is used.
     */
    public static class ManualWagonProvider implements WagonProvider {
        public Wagon lookup(String roleHint) throws Exception {
            if ("http".equals(roleHint)) {
                return new HttpWagon();
            }
            return null;
        }

        public void release(Wagon wagon) {

        }
    }
}