org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Igor Fedorenko
 * 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
 *
 * Contributors:
 *      Igor Fedorenko - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.core.internal.embedder;

import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Properties;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.properties.internal.EnvironmentUtils;

import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.transfer.TransferListener;

import org.eclipse.m2e.core.embedder.ICallable;
import org.eclipse.m2e.core.embedder.IMavenExecutionContext;

/**
 * @since 1.4
 */
public class MavenExecutionContext implements IMavenExecutionContext {
    private static final ThreadLocal<Deque<MavenExecutionContext>> context = new ThreadLocal<Deque<MavenExecutionContext>>();

    private final MavenImpl maven;

    private MavenExecutionRequest request;

    private ArtifactRepository localRepository;

    private FilterRepositorySystemSession repositorySession;

    private MavenSession mavenSession;

    public MavenExecutionContext(MavenImpl maven) {
        this.maven = maven;
    }

    public MavenExecutionRequest getExecutionRequest() throws CoreException {
        if (request != null && mavenSession != null) {
            return new ReadonlyMavenExecutionRequest(request);
        }
        if (request == null) {
            request = newExecutionRequest();
        }
        return request;
    }

    protected MavenExecutionRequest newExecutionRequest() throws CoreException {
        MavenExecutionRequest request = null;
        Deque<MavenExecutionContext> stack = context.get();
        if (stack != null && !stack.isEmpty()) {
            MavenExecutionRequest parent = stack.peek().request;
            if (parent == null) {
                throw new IllegalStateException(); // 
            }
            request = DefaultMavenExecutionRequest.copy(parent);
        }
        if (request == null) {
            request = maven.createExecutionRequest();
        }
        return request;
    }

    public <V> V execute(ICallable<V> callable, IProgressMonitor monitor) throws CoreException {
        return execute(null, callable, monitor);
    }

    public <V> V execute(MavenProject project, ICallable<V> callable, IProgressMonitor monitor)
            throws CoreException {
        Deque<MavenExecutionContext> stack = context.get();
        if (stack == null) {
            stack = new ArrayDeque<MavenExecutionContext>();
            context.set(stack);
        }
        final MavenExecutionContext parent = stack.peek();

        if (this == parent) {
            // shortcut the setup logic, this is nested invocation of the same context
            return executeBare(project, callable, monitor);
        }

        // remember original configuration to "pop" the session stack properly
        final ArtifactRepository origlocalRepository = localRepository;
        final FilterRepositorySystemSession origRepositorySession = repositorySession;
        final MavenSession origMavenSession = mavenSession;
        final MavenExecutionRequest origRequest = request;

        if (request == null && parent != null) {
            this.request = parent.request;
            this.localRepository = parent.localRepository;
            this.repositorySession = parent.repositorySession;
            this.mavenSession = parent.mavenSession;
        } else {
            if (request == null) {
                request = newExecutionRequest();
            }
            maven.populateDefaults(request);
            populateSystemProperties(request);
            this.localRepository = request.getLocalRepository();
            this.repositorySession = maven.createRepositorySession(request);
            if (parent != null) {
                this.repositorySession.setData(parent.repositorySession.getData());
            }
            final MavenExecutionResult result = new DefaultMavenExecutionResult();
            this.mavenSession = new MavenSession(maven.getPlexusContainer(), repositorySession, request, result);
        }

        final LegacySupport legacySupport = maven.lookup(LegacySupport.class);
        final MavenSession origLegacySession = legacySupport.getSession(); // TODO validate == origSession

        stack.push(this);
        legacySupport.setSession(mavenSession);
        try {
            return executeBare(project, callable, monitor);
        } finally {
            stack.pop();
            if (stack.isEmpty()) {
                context.set(null); // TODO decide if this is useful
            }
            legacySupport.setSession(origLegacySession);
            mavenSession = origMavenSession;
            repositorySession = origRepositorySession;
            localRepository = origlocalRepository;
            request = origRequest;
        }
    }

    private <V> V executeBare(MavenProject project, ICallable<V> callable, IProgressMonitor monitor)
            throws CoreException {
        final TransferListener origTransferListener = repositorySession
                .setTransferListener(maven.createArtifactTransferListener(monitor));
        final MavenProject origProject = mavenSession.getCurrentProject();
        final List<MavenProject> origProjects = mavenSession.getProjects();
        try {
            if (project != null) {
                mavenSession.setCurrentProject(project);
                mavenSession.setProjects(Collections.singletonList(project));
            }
            return callable.call(this, monitor);
        } finally {
            repositorySession.setTransferListener(origTransferListener);
            if (project != null) {
                mavenSession.setCurrentProject(origProject);
                mavenSession
                        .setProjects(origProjects != null ? origProjects : Collections.<MavenProject>emptyList());
            }
        }
    }

    public MavenSession getSession() {
        if (mavenSession == null) {
            throw new IllegalStateException();
        }
        return mavenSession;
    }

    public ArtifactRepository getLocalRepository() {
        if (mavenSession == null) {
            throw new IllegalStateException();
        }
        return localRepository;
    }

    public RepositorySystemSession getRepositorySession() {
        if (mavenSession == null) {
            throw new IllegalStateException();
        }
        return repositorySession;
    }

    public static MavenExecutionContext getThreadContext() {
        final Deque<MavenExecutionContext> stack = context.get();
        return stack != null ? stack.peek() : null;
    }

    public static void populateSystemProperties(MavenExecutionRequest request) {
        // temporary solution for https://issues.sonatype.org/browse/MNGECLIPSE-1607
        // oddly, there are no unit tests that fail if this is commented out
        Properties systemProperties = new Properties();
        EnvironmentUtils.addEnvVars(systemProperties);
        systemProperties.putAll(System.getProperties());
        request.setSystemProperties(systemProperties);
    }

    /*
     * <rant>Maven core does not provide good separation between session state, i.e. caches, settings, etc, and project
     * building configuration, i.e. if dependencies should be resolve, resolution leniency, etc. On top of that, there is
     * no easy way to create new populated ProjectBuildingRequest instances. Otherwise this method would not be
     * needed.</rant>
     */
    public ProjectBuildingRequest newProjectBuildingRequest() {
        DefaultProjectBuildingRequest projectBuildingRequest = new DefaultProjectBuildingRequest();
        projectBuildingRequest.setLocalRepository(getLocalRepository());
        projectBuildingRequest.setRepositorySession(getRepositorySession());
        projectBuildingRequest.setSystemProperties(request.getSystemProperties());
        projectBuildingRequest.setUserProperties(request.getUserProperties());
        projectBuildingRequest.setRemoteRepositories(request.getRemoteRepositories());
        projectBuildingRequest.setPluginArtifactRepositories(request.getPluginArtifactRepositories());
        projectBuildingRequest.setActiveProfileIds(request.getActiveProfiles());
        projectBuildingRequest.setInactiveProfileIds(request.getInactiveProfiles());
        projectBuildingRequest.setProfiles(request.getProfiles());
        projectBuildingRequest.setProcessPlugins(true);
        projectBuildingRequest.setBuildStartTime(request.getStartTime());
        return projectBuildingRequest;
    }

}