View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.transformation.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Provider;
24  
25  import java.nio.file.Path;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Properties;
31  import java.util.stream.Collectors;
32  
33  import org.apache.maven.api.model.Dependency;
34  import org.apache.maven.api.model.DependencyManagement;
35  import org.apache.maven.api.model.DistributionManagement;
36  import org.apache.maven.api.model.Model;
37  import org.apache.maven.api.model.ModelBase;
38  import org.apache.maven.api.model.Profile;
39  import org.apache.maven.api.model.Repository;
40  import org.apache.maven.model.building.DefaultModelBuilder;
41  import org.apache.maven.model.building.DefaultModelBuilderFactory;
42  import org.apache.maven.model.building.DefaultModelBuildingRequest;
43  import org.apache.maven.model.building.ModelBuildingException;
44  import org.apache.maven.model.building.ModelBuildingRequest;
45  import org.apache.maven.model.building.ModelBuildingResult;
46  import org.apache.maven.model.building.ModelProblemCollector;
47  import org.apache.maven.model.building.ModelProcessor;
48  import org.apache.maven.model.composition.DependencyManagementImporter;
49  import org.apache.maven.model.inheritance.InheritanceAssembler;
50  import org.apache.maven.model.interpolation.ModelInterpolator;
51  import org.apache.maven.model.management.DependencyManagementInjector;
52  import org.apache.maven.model.management.PluginManagementInjector;
53  import org.apache.maven.model.normalization.ModelNormalizer;
54  import org.apache.maven.model.path.ModelPathTranslator;
55  import org.apache.maven.model.path.ModelUrlNormalizer;
56  import org.apache.maven.model.plugin.LifecycleBindingsInjector;
57  import org.apache.maven.model.plugin.PluginConfigurationExpander;
58  import org.apache.maven.model.plugin.ReportConfigurationExpander;
59  import org.apache.maven.model.profile.DefaultProfileSelector;
60  import org.apache.maven.model.profile.ProfileActivationContext;
61  import org.apache.maven.model.profile.ProfileInjector;
62  import org.apache.maven.model.profile.ProfileSelector;
63  import org.apache.maven.model.superpom.SuperPomProvider;
64  import org.apache.maven.model.v4.MavenModelVersion;
65  import org.apache.maven.model.validation.ModelValidator;
66  import org.apache.maven.model.version.VersionParser;
67  import org.apache.maven.project.MavenProject;
68  import org.apache.maven.project.ProjectBuildingRequest;
69  import org.apache.maven.project.ProjectModelResolver;
70  import org.apache.maven.repository.internal.ModelCacheFactory;
71  import org.eclipse.aether.RepositorySystem;
72  import org.eclipse.aether.RepositorySystemSession;
73  import org.eclipse.aether.RequestTrace;
74  import org.eclipse.aether.impl.RemoteRepositoryManager;
75  
76  @Named
77  class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
78      private static final String BOM_PACKAGING = "bom";
79  
80      public static final String POM_PACKAGING = "pom";
81  
82      @Inject
83      private ModelCacheFactory modelCacheFactory;
84  
85      @Inject
86      private ProfileInjector profileInjector;
87  
88      @Inject
89      private InheritanceAssembler inheritanceAssembler;
90  
91      @Inject
92      private DependencyManagementImporter dependencyManagementImporter;
93  
94      @Inject
95      private DependencyManagementInjector dependencyManagementInjector;
96  
97      @Inject
98      private LifecycleBindingsInjector lifecycleBindingsInjector;
99  
100     @Inject
101     private ModelInterpolator modelInterpolator;
102 
103     @Inject
104     private ModelNormalizer modelNormalizer;
105 
106     @Inject
107     private ModelPathTranslator modelPathTranslator;
108 
109     @Inject
110     private ModelProcessor modelProcessor;
111 
112     @Inject
113     private ModelUrlNormalizer modelUrlNormalizer;
114 
115     @Inject
116     private ModelValidator modelValidator;
117 
118     @Inject
119     private PluginConfigurationExpander pluginConfigurationExpander;
120 
121     @Inject
122     private PluginManagementInjector pluginManagementInjector;
123 
124     @Inject
125     private ReportConfigurationExpander reportConfigurationExpander;
126 
127     @Inject
128     private SuperPomProvider superPomProvider;
129 
130     @Inject
131     private VersionParser versionParser;
132 
133     // To break circular dependency
134     @Inject
135     private Provider<RepositorySystem> repositorySystem;
136 
137     @Inject
138     private RemoteRepositoryManager remoteRepositoryManager;
139 
140     @Override
141     public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuildingException {
142         Model model = project.getModel().getDelegate();
143         String packaging = model.getPackaging();
144         String originalPackaging = project.getOriginalModel().getPackaging();
145         if (POM_PACKAGING.equals(packaging) && !BOM_PACKAGING.equals(originalPackaging)) {
146             return buildPom(session, project, src);
147         } else {
148             return buildNonPom(session, project, src);
149         }
150     }
151 
152     protected Model buildPom(RepositorySystemSession session, MavenProject project, Path src)
153             throws ModelBuildingException {
154         ModelBuildingResult result = buildModel(session, project, src);
155         Model model = result.getRawModel().getDelegate();
156         return transform(model, project);
157     }
158 
159     protected Model buildNonPom(RepositorySystemSession session, MavenProject project, Path src)
160             throws ModelBuildingException {
161         ModelBuildingResult result = buildModel(session, project, src);
162         Model model = result.getEffectiveModel().getDelegate();
163         return transform(model, project);
164     }
165 
166     private ModelBuildingResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
167             throws ModelBuildingException {
168         ProfileSelector customSelector = new DefaultProfileSelector() {
169             @Override
170             public List<Profile> getActiveProfilesV4(
171                     Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
172                 return new ArrayList<>();
173             }
174         };
175         DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory()
176                 .setProfileSelector(customSelector)
177                 // apply currently active ModelProcessor etc. to support extensions like jgitver
178                 .setProfileInjector(profileInjector)
179                 .setInheritanceAssembler(inheritanceAssembler)
180                 .setDependencyManagementImporter(dependencyManagementImporter)
181                 .setDependencyManagementInjector(dependencyManagementInjector)
182                 .setLifecycleBindingsInjector(lifecycleBindingsInjector)
183                 .setModelInterpolator(modelInterpolator)
184                 .setModelNormalizer(modelNormalizer)
185                 .setModelPathTranslator(modelPathTranslator)
186                 .setModelProcessor(modelProcessor)
187                 .setModelUrlNormalizer(modelUrlNormalizer)
188                 .setModelValidator(modelValidator)
189                 .setPluginConfigurationExpander(pluginConfigurationExpander)
190                 .setPluginManagementInjector(pluginManagementInjector)
191                 .setReportConfigurationExpander(reportConfigurationExpander)
192                 .setSuperPomProvider(superPomProvider)
193                 .setModelVersionParser(versionParser)
194                 .newInstance();
195         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
196         try {
197             request.setRootDirectory(project.getRootDirectory());
198         } catch (IllegalStateException e) {
199             // ignore if we don't have a root directory
200         }
201         request.setPomFile(src.toFile());
202         request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
203         request.setLocationTracking(false);
204         request.setModelResolver(new ProjectModelResolver(
205                 session,
206                 new RequestTrace(null),
207                 repositorySystem.get(),
208                 remoteRepositoryManager,
209                 project.getRemoteProjectRepositories(),
210                 ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT,
211                 null));
212         request.setTransformerContextBuilder(modelBuilder.newTransformerContextBuilder());
213         request.setSystemProperties(toProperties(session.getSystemProperties()));
214         request.setUserProperties(toProperties(session.getUserProperties()));
215         request.setModelCache(modelCacheFactory.createCache(session));
216         return modelBuilder.build(request);
217     }
218 
219     private Properties toProperties(Map<String, String> map) {
220         Properties props = new Properties();
221         props.putAll(map);
222         return props;
223     }
224 
225     static Model transform(Model model, MavenProject project) {
226         String packaging = model.getPackaging();
227         if (POM_PACKAGING.equals(packaging)) {
228             // raw to consumer transform
229             model = model.withRoot(false).withModules(null);
230             if (model.getParent() != null) {
231                 model = model.withParent(model.getParent().withRelativePath(null));
232             }
233 
234             if (!model.isPreserveModelVersion()) {
235                 model = model.withPreserveModelVersion(false);
236                 String modelVersion = new MavenModelVersion().getModelVersion(model);
237                 model = model.withModelVersion(modelVersion);
238             }
239         } else if (BOM_PACKAGING.equals(packaging)) {
240             DependencyManagement dependencyManagement =
241                     project.getOriginalModel().getDependencyManagement().getDelegate();
242             List<Dependency> dependencies = new ArrayList<>();
243             String version = model.getVersion();
244 
245             dependencyManagement
246                     .getDependencies()
247                     .forEach((dependency) -> dependencies.add(dependency.withVersion(version)));
248             Model.Builder builder = prune(
249                     Model.newBuilder(model, true)
250                             .preserveModelVersion(false)
251                             .root(false)
252                             .parent(null)
253                             .dependencyManagement(dependencyManagement.withDependencies(dependencies))
254                             .build(null),
255                     model);
256             builder.packaging(POM_PACKAGING);
257             builder.profiles(model.getProfiles().stream()
258                     .map(p -> prune(Profile.newBuilder(p, true), p).build())
259                     .collect(Collectors.toList()));
260 
261             model = builder.build();
262             String modelVersion = new MavenModelVersion().getModelVersion(model);
263             model = model.withModelVersion(modelVersion);
264         } else {
265             Model.Builder builder = prune(
266                     Model.newBuilder(model, true)
267                             .preserveModelVersion(false)
268                             .root(false)
269                             .parent(null)
270                             .build(null),
271                     model);
272             builder.profiles(model.getProfiles().stream()
273                     .map(p -> prune(Profile.newBuilder(p, true), p).build())
274                     .collect(Collectors.toList()));
275             model = builder.build();
276             String modelVersion = new MavenModelVersion().getModelVersion(model);
277             model = model.withModelVersion(modelVersion);
278         }
279         return model;
280     }
281 
282     private static <T extends ModelBase.Builder> T prune(T builder, ModelBase model) {
283         builder.properties(null).reporting(null);
284         if (model.getDistributionManagement() != null
285                 && model.getDistributionManagement().getRelocation() != null) {
286             // keep relocation only
287             builder.distributionManagement(DistributionManagement.newBuilder()
288                     .relocation(model.getDistributionManagement().getRelocation())
289                     .build());
290         }
291         // only keep repositories other than 'central'
292         builder.pluginRepositories(pruneRepositories(model.getPluginRepositories()));
293         builder.repositories(pruneRepositories(model.getRepositories()));
294         return builder;
295     }
296 
297     private static List<Repository> pruneRepositories(List<Repository> repositories) {
298         return repositories.stream()
299                 .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
300                 .collect(Collectors.toList());
301     }
302 }