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.List;
27  import java.util.stream.Collectors;
28  
29  import org.apache.maven.api.SessionData;
30  import org.apache.maven.api.model.Dependency;
31  import org.apache.maven.api.model.DependencyManagement;
32  import org.apache.maven.api.model.DistributionManagement;
33  import org.apache.maven.api.model.Model;
34  import org.apache.maven.api.model.ModelBase;
35  import org.apache.maven.api.model.Profile;
36  import org.apache.maven.api.model.Repository;
37  import org.apache.maven.api.services.ModelBuilder;
38  import org.apache.maven.api.services.ModelBuilderException;
39  import org.apache.maven.api.services.ModelBuilderRequest;
40  import org.apache.maven.api.services.ModelBuilderResult;
41  import org.apache.maven.api.services.ModelSource;
42  import org.apache.maven.api.services.model.LifecycleBindingsInjector;
43  import org.apache.maven.internal.impl.InternalSession;
44  import org.apache.maven.model.v4.MavenModelVersion;
45  import org.apache.maven.project.MavenProject;
46  import org.eclipse.aether.RepositorySystemSession;
47  
48  @Named
49  class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
50      private static final String BOM_PACKAGING = "bom";
51  
52      public static final String POM_PACKAGING = "pom";
53  
54      private final LifecycleBindingsInjector lifecycleBindingsInjector;
55  
56      @Inject
57      @SuppressWarnings("checkstyle:ParameterNumber")
58      DefaultConsumerPomBuilder(LifecycleBindingsInjector lifecycleBindingsInjector) {
59          this.lifecycleBindingsInjector = lifecycleBindingsInjector;
60      }
61  
62      @Override
63      public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuilderException {
64          Model model = project.getModel().getDelegate();
65          String packaging = model.getPackaging();
66          String originalPackaging = project.getOriginalModel().getPackaging();
67          if (POM_PACKAGING.equals(packaging) && !BOM_PACKAGING.equals(originalPackaging)) {
68              return buildPom(session, project, src);
69          } else {
70              return buildNonPom(session, project, src);
71          }
72      }
73  
74      protected Model buildPom(RepositorySystemSession session, MavenProject project, Path src)
75              throws ModelBuilderException {
76          ModelBuilderResult result = buildModel(session, project, src);
77          Model model = result.getRawModel();
78          return transform(model, project);
79      }
80  
81      protected Model buildNonPom(RepositorySystemSession session, MavenProject project, Path src)
82              throws ModelBuilderException {
83          ModelBuilderResult result = buildModel(session, project, src);
84          Model model = result.getEffectiveModel();
85          return transform(model, project);
86      }
87  
88      private ModelBuilderResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
89              throws ModelBuilderException {
90          InternalSession iSession = InternalSession.from(session);
91          ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
92          request.requestType(ModelBuilderRequest.RequestType.BUILD_CONSUMER);
93          request.session(iSession);
94          request.source(ModelSource.fromPath(src));
95          request.locationTracking(false);
96          request.systemProperties(session.getSystemProperties());
97          request.userProperties(session.getUserProperties());
98          request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings);
99          ModelBuilder.ModelBuilderSession mbSession =
100                 iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class));
101         return mbSession.build(request.build());
102     }
103 
104     static Model transform(Model model, MavenProject project) {
105         String packaging = model.getPackaging();
106         if (POM_PACKAGING.equals(packaging)) {
107             // raw to consumer transform
108             model = model.withRoot(false).withModules(null).withSubprojects(null);
109             if (model.getParent() != null) {
110                 model = model.withParent(model.getParent().withRelativePath(null));
111             }
112 
113             if (!model.isPreserveModelVersion()) {
114                 model = model.withPreserveModelVersion(false);
115                 String modelVersion = new MavenModelVersion().getModelVersion(model);
116                 model = model.withModelVersion(modelVersion);
117             }
118         } else if (BOM_PACKAGING.equals(packaging)) {
119             DependencyManagement dependencyManagement =
120                     project.getOriginalModel().getDependencyManagement().getDelegate();
121             List<Dependency> dependencies = new ArrayList<>();
122             String version = model.getVersion();
123 
124             dependencyManagement
125                     .getDependencies()
126                     .forEach((dependency) -> dependencies.add(dependency.withVersion(version)));
127             Model.Builder builder = prune(
128                     Model.newBuilder(model, true)
129                             .preserveModelVersion(false)
130                             .root(false)
131                             .parent(null)
132                             .dependencyManagement(dependencyManagement.withDependencies(dependencies))
133                             .build(null),
134                     model);
135             builder.packaging(POM_PACKAGING);
136             builder.profiles(prune(model.getProfiles()));
137 
138             model = builder.build();
139             String modelVersion = new MavenModelVersion().getModelVersion(model);
140             model = model.withModelVersion(modelVersion);
141         } else {
142             Model.Builder builder = prune(
143                     Model.newBuilder(model, true)
144                             .preserveModelVersion(false)
145                             .root(false)
146                             .parent(null)
147                             .build(null),
148                     model);
149             builder.profiles(prune(model.getProfiles()));
150 
151             model = builder.build();
152             String modelVersion = new MavenModelVersion().getModelVersion(model);
153             model = model.withModelVersion(modelVersion);
154         }
155         return model;
156     }
157 
158     private static List<Profile> prune(List<Profile> profiles) {
159         return profiles.stream()
160                 .map(p -> {
161                     Profile.Builder builder = Profile.newBuilder(p, true);
162                     prune((ModelBase.Builder) builder, p);
163                     return builder.build(null).build();
164                 })
165                 .filter(p -> !isEmpty(p))
166                 .collect(Collectors.toList());
167     }
168 
169     private static boolean isEmpty(Profile profile) {
170         return profile.getActivation() == null
171                 && profile.getBuild() == null
172                 && profile.getDependencies().isEmpty()
173                 && (profile.getDependencyManagement() == null
174                         || profile.getDependencyManagement().getDependencies().isEmpty())
175                 && profile.getDistributionManagement() == null
176                 && profile.getModules().isEmpty()
177                 && profile.getSubprojects().isEmpty()
178                 && profile.getProperties().isEmpty()
179                 && profile.getRepositories().isEmpty()
180                 && profile.getPluginRepositories().isEmpty()
181                 && profile.getReporting() == null;
182     }
183 
184     private static <T extends ModelBase.Builder> T prune(T builder, ModelBase model) {
185         builder.properties(null).reporting(null);
186         if (model.getDistributionManagement() != null
187                 && model.getDistributionManagement().getRelocation() != null) {
188             // keep relocation only
189             builder.distributionManagement(DistributionManagement.newBuilder()
190                     .relocation(model.getDistributionManagement().getRelocation())
191                     .build());
192         }
193         // only keep repositories other than 'central'
194         builder.pluginRepositories(pruneRepositories(model.getPluginRepositories()));
195         builder.repositories(pruneRepositories(model.getRepositories()));
196         return builder;
197     }
198 
199     private static List<Repository> pruneRepositories(List<Repository> repositories) {
200         return repositories.stream()
201                 .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
202                 .collect(Collectors.toList());
203     }
204 }