1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import org.apache.maven.RepositoryUtils;
36 import org.apache.maven.api.xml.XmlNode;
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.InvalidRepositoryException;
39 import org.apache.maven.artifact.repository.ArtifactRepository;
40 import org.apache.maven.bridge.MavenRepositorySystem;
41 import org.apache.maven.classrealm.ClassRealmManager;
42 import org.apache.maven.model.Build;
43 import org.apache.maven.model.Extension;
44 import org.apache.maven.model.Model;
45 import org.apache.maven.model.Plugin;
46 import org.apache.maven.model.Repository;
47 import org.apache.maven.plugin.ExtensionRealmCache;
48 import org.apache.maven.plugin.MavenPluginManager;
49 import org.apache.maven.plugin.PluginManagerException;
50 import org.apache.maven.plugin.PluginResolutionException;
51 import org.apache.maven.plugin.version.PluginVersionResolutionException;
52 import org.codehaus.plexus.classworlds.realm.ClassRealm;
53 import org.codehaus.plexus.util.xml.Xpp3Dom;
54 import org.eclipse.aether.graph.DependencyFilter;
55 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59
60
61
62
63
64
65 @Named
66 @Singleton
67 public class DefaultProjectBuildingHelper implements ProjectBuildingHelper {
68 private final Logger logger = LoggerFactory.getLogger(getClass());
69 private final ClassRealmManager classRealmManager;
70 private final ProjectRealmCache projectRealmCache;
71 private final MavenRepositorySystem repositorySystem;
72 private final MavenPluginManager pluginManager;
73
74 @Inject
75 public DefaultProjectBuildingHelper(
76 ClassRealmManager classRealmManager,
77 ProjectRealmCache projectRealmCache,
78 MavenRepositorySystem repositorySystem,
79 MavenPluginManager pluginManager) {
80 this.classRealmManager = classRealmManager;
81 this.projectRealmCache = projectRealmCache;
82 this.repositorySystem = repositorySystem;
83 this.pluginManager = pluginManager;
84 }
85
86 public List<ArtifactRepository> createArtifactRepositories(
87 List<Repository> pomRepositories,
88 List<ArtifactRepository> externalRepositories,
89 ProjectBuildingRequest request)
90 throws InvalidRepositoryException {
91 List<ArtifactRepository> internalRepositories = new ArrayList<>();
92
93 for (Repository repository : pomRepositories) {
94 internalRepositories.add(MavenRepositorySystem.buildArtifactRepository(repository));
95 }
96
97 repositorySystem.injectMirror(request.getRepositorySession(), internalRepositories);
98
99 repositorySystem.injectProxy(request.getRepositorySession(), internalRepositories);
100
101 repositorySystem.injectAuthentication(request.getRepositorySession(), internalRepositories);
102
103 List<ArtifactRepository> dominantRepositories;
104 List<ArtifactRepository> recessiveRepositories;
105
106 if (ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals(request.getRepositoryMerging())) {
107 dominantRepositories = externalRepositories;
108 recessiveRepositories = internalRepositories;
109 } else {
110 dominantRepositories = internalRepositories;
111 recessiveRepositories = externalRepositories;
112 }
113
114 List<ArtifactRepository> artifactRepositories = new ArrayList<>();
115 Collection<String> repoIds = new HashSet<>();
116
117 if (dominantRepositories != null) {
118 for (ArtifactRepository repository : dominantRepositories) {
119 repoIds.add(repository.getId());
120 artifactRepositories.add(repository);
121 }
122 }
123
124 if (recessiveRepositories != null) {
125 for (ArtifactRepository repository : recessiveRepositories) {
126 if (repoIds.add(repository.getId())) {
127 artifactRepositories.add(repository);
128 }
129 }
130 }
131
132 artifactRepositories = repositorySystem.getEffectiveRepositories(artifactRepositories);
133
134 return artifactRepositories;
135 }
136
137 public synchronized ProjectRealmCache.CacheRecord createProjectRealm(
138 MavenProject project, Model model, ProjectBuildingRequest request)
139 throws PluginResolutionException, PluginVersionResolutionException, PluginManagerException {
140 ClassRealm projectRealm;
141
142 List<Plugin> extensionPlugins = new ArrayList<>();
143
144 Build build = model.getBuild();
145
146 if (build != null) {
147 for (Extension extension : build.getExtensions()) {
148 Plugin plugin = new Plugin();
149 plugin.setGroupId(extension.getGroupId());
150 plugin.setArtifactId(extension.getArtifactId());
151 plugin.setVersion(extension.getVersion());
152 XmlNode configuration = extension.getDelegate().getConfiguration();
153 if (configuration != null) {
154 plugin.setConfiguration(new Xpp3Dom(configuration));
155 }
156 extensionPlugins.add(plugin);
157 }
158
159 for (Plugin plugin : build.getPlugins()) {
160 if (plugin.isExtensions()) {
161 extensionPlugins.add(plugin);
162 }
163 }
164 }
165
166 if (extensionPlugins.isEmpty()) {
167 if (logger.isDebugEnabled()) {
168 logger.debug("Extension realms for project " + model.getId() + ": (none)");
169 }
170
171 return new ProjectRealmCache.CacheRecord(null, null);
172 }
173
174 List<ClassRealm> extensionRealms = new ArrayList<>();
175
176 Map<ClassRealm, List<String>> exportedPackages = new HashMap<>();
177
178 Map<ClassRealm, List<String>> exportedArtifacts = new HashMap<>();
179
180 List<Artifact> publicArtifacts = new ArrayList<>();
181
182 for (Plugin plugin : extensionPlugins) {
183 ExtensionRealmCache.CacheRecord recordRealm =
184 pluginManager.setupExtensionsRealm(project, plugin, request.getRepositorySession());
185
186 final ClassRealm extensionRealm = recordRealm.getRealm();
187 final ExtensionDescriptor extensionDescriptor = recordRealm.getDescriptor();
188 final List<Artifact> artifacts = recordRealm.getArtifacts();
189
190 extensionRealms.add(extensionRealm);
191 if (extensionDescriptor != null) {
192 exportedPackages.put(extensionRealm, extensionDescriptor.getExportedPackages());
193 exportedArtifacts.put(extensionRealm, extensionDescriptor.getExportedArtifacts());
194 }
195
196 if (!plugin.isExtensions()
197 && artifacts.size() == 1
198 && artifacts.get(0).getFile() != null) {
199
200
201
202
203
204 publicArtifacts.addAll(artifacts);
205 }
206 }
207
208 if (logger.isDebugEnabled()) {
209 logger.debug("Extension realms for project " + model.getId() + ": " + extensionRealms);
210 }
211
212 ProjectRealmCache.Key projectRealmKey = projectRealmCache.createKey(extensionRealms);
213
214 ProjectRealmCache.CacheRecord record = projectRealmCache.get(projectRealmKey);
215
216 if (record == null) {
217 projectRealm = classRealmManager.createProjectRealm(model, toAetherArtifacts(publicArtifacts));
218
219 Set<String> exclusions = new LinkedHashSet<>();
220
221 for (ClassRealm extensionRealm : extensionRealms) {
222 List<String> excludes = exportedArtifacts.get(extensionRealm);
223
224 if (excludes != null) {
225 exclusions.addAll(excludes);
226 }
227
228 List<String> exports = exportedPackages.get(extensionRealm);
229
230 if (exports == null || exports.isEmpty()) {
231
232
233
234
235
236 exports = Arrays.asList(extensionRealm.getId());
237 }
238
239 for (String export : exports) {
240 projectRealm.importFrom(extensionRealm, export);
241 }
242 }
243
244 DependencyFilter extensionArtifactFilter = null;
245 if (!exclusions.isEmpty()) {
246 extensionArtifactFilter = new ExclusionsDependencyFilter(exclusions);
247 }
248
249 record = projectRealmCache.put(projectRealmKey, projectRealm, extensionArtifactFilter);
250 }
251
252 projectRealmCache.register(project, projectRealmKey, record);
253
254 return record;
255 }
256
257 public void selectProjectRealm(MavenProject project) {
258 ClassLoader projectRealm = project.getClassRealm();
259
260 if (projectRealm == null) {
261 projectRealm = classRealmManager.getCoreRealm();
262 }
263
264 Thread.currentThread().setContextClassLoader(projectRealm);
265 }
266
267 private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) {
268 return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
269 }
270 }