001package org.apache.maven.cli.internal;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.List;
026import java.util.Set;
027
028import javax.inject.Inject;
029import javax.inject.Named;
030
031import org.apache.maven.RepositoryUtils;
032import org.apache.maven.cli.internal.extension.model.CoreExtension;
033import org.apache.maven.execution.MavenExecutionRequest;
034import org.apache.maven.extension.internal.CoreExtensionEntry;
035import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
036import org.apache.maven.model.Plugin;
037import org.apache.maven.plugin.PluginResolutionException;
038import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
039import org.codehaus.plexus.DefaultPlexusContainer;
040import org.codehaus.plexus.PlexusContainer;
041import org.codehaus.plexus.classworlds.ClassWorld;
042import org.codehaus.plexus.classworlds.realm.ClassRealm;
043import org.codehaus.plexus.logging.Logger;
044import org.eclipse.aether.RepositorySystemSession;
045import org.eclipse.aether.artifact.Artifact;
046import org.eclipse.aether.graph.DependencyFilter;
047import org.eclipse.aether.graph.DependencyNode;
048import org.eclipse.aether.repository.RemoteRepository;
049import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
050import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
051
052@Named
053public class BootstrapCoreExtensionManager
054{
055    private final Logger log;
056
057    private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
058
059    private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
060
061    private final ClassWorld classWorld;
062
063    private final ClassRealm parentRealm;
064
065    @Inject
066    public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver,
067                                          DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
068                                          PlexusContainer container )
069    {
070        this.log = log;
071        this.pluginDependenciesResolver = pluginDependenciesResolver;
072        this.repositorySystemSessionFactory = repositorySystemSessionFactory;
073        this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
074        this.parentRealm = container.getContainerRealm();
075    }
076
077    public List<CoreExtensionEntry> loadCoreExtensions( MavenExecutionRequest request, Set<String> providedArtifacts,
078                                                        List<CoreExtension> extensions )
079        throws Exception
080    {
081        RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request );
082        List<RemoteRepository> repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() );
083
084        return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions );
085    }
086
087    private List<CoreExtensionEntry> resolveCoreExtensions( RepositorySystemSession repoSession,
088                                                            List<RemoteRepository> repositories,
089                                                            Set<String> providedArtifacts,
090                                                            List<CoreExtension> configuration )
091        throws Exception
092    {
093        List<CoreExtensionEntry> extensions = new ArrayList<>();
094
095        DependencyFilter dependencyFilter = new ExclusionsDependencyFilter( providedArtifacts );
096
097        for ( CoreExtension extension : configuration )
098        {
099            List<Artifact> artifacts = resolveExtension( extension, repoSession, repositories, dependencyFilter );
100            if ( !artifacts.isEmpty() )
101            {
102                extensions.add( createExtension( extension, artifacts ) );
103            }
104        }
105
106        return Collections.unmodifiableList( extensions );
107    }
108
109    private CoreExtensionEntry createExtension( CoreExtension extension, List<Artifact> artifacts )
110        throws Exception
111    {
112        String realmId =
113            "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
114        ClassRealm realm = classWorld.newRealm( realmId, null );
115        log.debug( "Populating class realm " + realm.getId() );
116        realm.setParentRealm( parentRealm );
117        for ( Artifact artifact : artifacts )
118        {
119            File file = artifact.getFile();
120            log.debug( "  Included " + file );
121            realm.addURL( file.toURI().toURL() );
122        }
123        return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
124    }
125
126    private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
127                                             List<RemoteRepository> repositories, DependencyFilter dependencyFilter )
128        throws PluginResolutionException
129    {
130        Plugin plugin = new Plugin();
131        plugin.setGroupId( extension.getGroupId() );
132        plugin.setArtifactId( extension.getArtifactId() );
133        plugin.setVersion( extension.getVersion() );
134
135        DependencyNode root =
136            pluginDependenciesResolver.resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
137        PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
138        root.accept( nlg );
139        List<Artifact> artifacts = nlg.getArtifacts( false );
140
141        return artifacts;
142    }
143}