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  
24  import java.nio.file.Path;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.api.model.Dependency;
33  import org.apache.maven.api.model.DependencyManagement;
34  import org.apache.maven.api.model.DistributionManagement;
35  import org.apache.maven.api.model.Model;
36  import org.apache.maven.api.model.ModelBase;
37  import org.apache.maven.api.model.Profile;
38  import org.apache.maven.api.model.Repository;
39  import org.apache.maven.model.building.DefaultModelBuilder;
40  import org.apache.maven.model.building.DefaultModelBuilderFactory;
41  import org.apache.maven.model.building.DefaultModelBuildingRequest;
42  import org.apache.maven.model.building.ModelBuildingException;
43  import org.apache.maven.model.building.ModelBuildingRequest;
44  import org.apache.maven.model.building.ModelBuildingResult;
45  import org.apache.maven.model.building.ModelProblemCollector;
46  import org.apache.maven.model.building.ModelProcessor;
47  import org.apache.maven.model.composition.DependencyManagementImporter;
48  import org.apache.maven.model.inheritance.InheritanceAssembler;
49  import org.apache.maven.model.interpolation.ModelInterpolator;
50  import org.apache.maven.model.management.DependencyManagementInjector;
51  import org.apache.maven.model.management.PluginManagementInjector;
52  import org.apache.maven.model.normalization.ModelNormalizer;
53  import org.apache.maven.model.path.ModelPathTranslator;
54  import org.apache.maven.model.path.ModelUrlNormalizer;
55  import org.apache.maven.model.plugin.LifecycleBindingsInjector;
56  import org.apache.maven.model.plugin.PluginConfigurationExpander;
57  import org.apache.maven.model.plugin.ReportConfigurationExpander;
58  import org.apache.maven.model.profile.DefaultProfileSelector;
59  import org.apache.maven.model.profile.ProfileActivationContext;
60  import org.apache.maven.model.profile.ProfileInjector;
61  import org.apache.maven.model.profile.ProfileSelector;
62  import org.apache.maven.model.superpom.SuperPomProvider;
63  import org.apache.maven.model.v4.MavenModelVersion;
64  import org.apache.maven.model.validation.ModelValidator;
65  import org.apache.maven.project.MavenProject;
66  import org.apache.maven.project.ProjectBuildingRequest;
67  import org.apache.maven.project.ProjectModelResolver;
68  import org.apache.maven.repository.internal.ModelCacheFactory;
69  import org.codehaus.plexus.PlexusContainer;
70  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
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  import org.slf4j.Logger;
76  import org.slf4j.LoggerFactory;
77  
78  @Named
79  class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
80      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConsumerPomBuilder.class);
81  
82      private static final String BOM_PACKAGING = "bom";
83  
84      public static final String POM_PACKAGING = "pom";
85  
86      @Inject
87      PlexusContainer container;
88  
89      @Inject
90      ModelCacheFactory modelCacheFactory;
91  
92      public Model build(RepositorySystemSession session, MavenProject project, Path src)
93              throws ModelBuildingException, ComponentLookupException {
94          Model model = project.getModel().getDelegate();
95          String packaging = model.getPackaging();
96          String originalPackaging = project.getOriginalModel().getPackaging();
97          if (POM_PACKAGING.equals(packaging) && !BOM_PACKAGING.equals(originalPackaging)) {
98              return buildPom(session, project, src);
99          } else {
100             return buildNonPom(session, project, src);
101         }
102     }
103 
104     protected Model buildPom(RepositorySystemSession session, MavenProject project, Path src)
105             throws ModelBuildingException, ComponentLookupException {
106         ModelBuildingResult result = buildModel(session, project, src);
107         Model model = result.getRawModel().getDelegate();
108         return transform(model, project);
109     }
110 
111     protected Model buildNonPom(RepositorySystemSession session, MavenProject project, Path src)
112             throws ModelBuildingException, ComponentLookupException {
113         ModelBuildingResult result = buildModel(session, project, src);
114         Model model = result.getEffectiveModel().getDelegate();
115         return transform(model, project);
116     }
117 
118     private ModelBuildingResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
119             throws ModelBuildingException, ComponentLookupException {
120         ProfileSelector customSelector = new DefaultProfileSelector() {
121             @Override
122             public List<Profile> getActiveProfilesV4(
123                     Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
124                 return new ArrayList<>();
125             }
126         };
127         DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory()
128                 .setProfileSelector(customSelector)
129                 // apply currently active ModelProcessor etc. to support extensions like jgitver
130                 .setProfileInjector(lookup(ProfileInjector.class))
131                 .setInheritanceAssembler(lookup(InheritanceAssembler.class))
132                 .setDependencyManagementImporter(lookup(DependencyManagementImporter.class))
133                 .setDependencyManagementInjector(lookup(DependencyManagementInjector.class))
134                 .setLifecycleBindingsInjector(lookup(LifecycleBindingsInjector.class))
135                 .setModelInterpolator(lookup(ModelInterpolator.class))
136                 .setModelNormalizer(lookup(ModelNormalizer.class))
137                 .setModelPathTranslator(lookup(ModelPathTranslator.class))
138                 .setModelProcessor(lookup(ModelProcessor.class))
139                 .setModelUrlNormalizer(lookup(ModelUrlNormalizer.class))
140                 .setModelValidator(lookup(ModelValidator.class))
141                 .setPluginConfigurationExpander(lookup(PluginConfigurationExpander.class))
142                 .setPluginManagementInjector(lookup(PluginManagementInjector.class))
143                 .setReportConfigurationExpander(lookup(ReportConfigurationExpander.class))
144                 .setSuperPomProvider(lookup(SuperPomProvider.class))
145                 .newInstance();
146         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
147         try {
148             request.setRootDirectory(project.getRootDirectory());
149         } catch (IllegalStateException e) {
150             // ignore if we don't have a root directory
151         }
152         request.setPomFile(src.toFile());
153         request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
154         request.setLocationTracking(false);
155         request.setModelResolver(new ProjectModelResolver(
156                 session,
157                 new RequestTrace(null),
158                 lookup(RepositorySystem.class),
159                 lookup(RemoteRepositoryManager.class),
160                 project.getRemoteProjectRepositories(),
161                 ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT,
162                 null));
163         request.setTransformerContextBuilder(modelBuilder.newTransformerContextBuilder());
164         request.setSystemProperties(toProperties(session.getSystemProperties()));
165         request.setUserProperties(toProperties(session.getUserProperties()));
166         request.setModelCache(modelCacheFactory.createCache(session));
167         return modelBuilder.build(request);
168     }
169 
170     private Properties toProperties(Map<String, String> map) {
171         Properties props = new Properties();
172         props.putAll(map);
173         return props;
174     }
175 
176     private <T> T lookup(Class<T> clazz) throws ComponentLookupException {
177         return container.lookup(clazz);
178     }
179 
180     static Model transform(Model model, MavenProject project) {
181         String packaging = model.getPackaging();
182         if (POM_PACKAGING.equals(packaging)) {
183             // raw to consumer transform
184             model = model.withRoot(false).withModules(null);
185             if (model.getParent() != null) {
186                 model = model.withParent(model.getParent().withRelativePath(null));
187             }
188 
189             if (!model.isPreserveModelVersion()) {
190                 model = model.withPreserveModelVersion(false);
191                 String modelVersion = new MavenModelVersion().getModelVersion(model);
192                 model = model.withModelVersion(modelVersion);
193             }
194         } else if (BOM_PACKAGING.equals(packaging)) {
195             DependencyManagement dependencyManagement =
196                     project.getOriginalModel().getDependencyManagement().getDelegate();
197             List<Dependency> dependencies = new ArrayList<>();
198             String version = model.getVersion();
199 
200             dependencyManagement
201                     .getDependencies()
202                     .forEach((dependency) -> dependencies.add(dependency.withVersion(version)));
203             Model.Builder builder = prune(
204                     Model.newBuilder(model, true)
205                             .preserveModelVersion(false)
206                             .root(false)
207                             .parent(null)
208                             .dependencyManagement(dependencyManagement.withDependencies(dependencies))
209                             .build(null),
210                     model);
211             builder.packaging(POM_PACKAGING);
212             builder.profiles(model.getProfiles().stream()
213                     .map(p -> prune(Profile.newBuilder(p, true), p).build())
214                     .collect(Collectors.toList()));
215 
216             model = builder.build();
217             String modelVersion = new MavenModelVersion().getModelVersion(model);
218             model = model.withModelVersion(modelVersion);
219         } else {
220             Model.Builder builder = prune(
221                     Model.newBuilder(model, true)
222                             .preserveModelVersion(false)
223                             .root(false)
224                             .parent(null)
225                             .build(null),
226                     model);
227             builder.profiles(model.getProfiles().stream()
228                     .map(p -> prune(Profile.newBuilder(p, true), p).build())
229                     .collect(Collectors.toList()));
230             model = builder.build();
231             String modelVersion = new MavenModelVersion().getModelVersion(model);
232             model = model.withModelVersion(modelVersion);
233         }
234         return model;
235     }
236 
237     private static <T extends ModelBase.Builder> T prune(T builder, ModelBase model) {
238         builder.properties(null).reporting(null);
239         if (model.getDistributionManagement() != null
240                 && model.getDistributionManagement().getRelocation() != null) {
241             // keep relocation only
242             builder.distributionManagement(DistributionManagement.newBuilder()
243                     .relocation(model.getDistributionManagement().getRelocation())
244                     .build());
245         }
246         // only keep repositories other than 'central'
247         builder.pluginRepositories(pruneRepositories(model.getPluginRepositories()));
248         builder.repositories(pruneRepositories(model.getRepositories()));
249         return builder;
250     }
251 
252     private static List<Repository> pruneRepositories(List<Repository> repositories) {
253         return repositories.stream()
254                 .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
255                 .collect(Collectors.toList());
256     }
257 }