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}