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.model.building;
20  
21  import java.nio.file.Files;
22  import java.nio.file.Path;
23  import java.util.ArrayList;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.concurrent.ConcurrentHashMap;
29  
30  import org.apache.maven.model.Model;
31  import org.apache.maven.model.building.DefaultTransformerContext.GAKey;
32  import org.apache.maven.model.building.DefaultTransformerContext.Holder;
33  
34  /**
35   * Builds up the transformer context.
36   * After the buildplan is ready, the build()-method returns the immutable context useful during distribution.
37   * This is an inner class, as it must be able to call readRawModel()
38   *
39   * @since 4.0.0
40   * @deprecated use {@link org.apache.maven.api.services.ModelBuilder} instead
41   */
42  @Deprecated(since = "4.0.0")
43  class DefaultTransformerContextBuilder implements TransformerContextBuilder {
44      private final Graph dag = new Graph();
45      private final DefaultModelBuilder defaultModelBuilder;
46      private final DefaultTransformerContext context;
47  
48      private final Map<String, Set<FileModelSource>> mappedSources = new ConcurrentHashMap<>(64);
49  
50      private volatile boolean fullReactorLoaded;
51  
52      DefaultTransformerContextBuilder(DefaultModelBuilder defaultModelBuilder) {
53          this.defaultModelBuilder = defaultModelBuilder;
54          this.context = new DefaultTransformerContext(defaultModelBuilder.getModelProcessor());
55      }
56  
57      /**
58       * If an interface could be extracted, DefaultModelProblemCollector should be ModelProblemCollectorExt
59       */
60      @Override
61      public TransformerContext initialize(ModelBuildingRequest request, ModelProblemCollector collector) {
62          // We must assume the TransformerContext was created using this.newTransformerContextBuilder()
63          DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector;
64          return new TransformerContext() {
65  
66              @Override
67              public Path locate(Path path) {
68                  return context.locate(path);
69              }
70  
71              @Override
72              public String getUserProperty(String key) {
73                  return context.userProperties.computeIfAbsent(
74                          key, k -> request.getUserProperties().getProperty(key));
75              }
76  
77              @Override
78              public Model getRawModel(Path from, String gId, String aId) {
79                  Model model = findRawModel(from, gId, aId);
80                  if (model != null) {
81                      context.modelByGA.put(new GAKey(gId, aId), new Holder(model));
82                      context.modelByPath.put(model.getPomPath(), new Holder(model));
83                  }
84                  return model;
85              }
86  
87              @Override
88              public Model getRawModel(Path from, Path path) {
89                  Model model = findRawModel(from, path);
90                  if (model != null) {
91                      String groupId = defaultModelBuilder.getGroupId(model);
92                      context.modelByGA.put(
93                              new DefaultTransformerContext.GAKey(groupId, model.getArtifactId()), new Holder(model));
94                      context.modelByPath.put(path, new Holder(model));
95                  }
96                  return model;
97              }
98  
99              private Model findRawModel(Path from, String groupId, String artifactId) {
100                 FileModelSource source = getSource(groupId, artifactId);
101                 if (source == null) {
102                     // we need to check the whole reactor in case it's a dependency
103                     loadFullReactor();
104                     source = getSource(groupId, artifactId);
105                 }
106                 if (source != null) {
107                     if (!addEdge(from, source.getPath(), problems)) {
108                         return null;
109                     }
110                     try {
111                         ModelBuildingRequest gaBuildingRequest =
112                                 new DefaultModelBuildingRequest(request).setModelSource(source);
113                         return defaultModelBuilder.readRawModel(gaBuildingRequest, problems);
114                     } catch (ModelBuildingException e) {
115                         // gathered with problem collector
116                     }
117                 }
118                 return null;
119             }
120 
121             private void loadFullReactor() {
122                 if (!fullReactorLoaded) {
123                     synchronized (DefaultTransformerContextBuilder.this) {
124                         if (!fullReactorLoaded) {
125                             doLoadFullReactor();
126                             fullReactorLoaded = true;
127                         }
128                     }
129                 }
130             }
131 
132             private void doLoadFullReactor() {
133                 Path rootDirectory = request.getRootDirectory();
134                 if (rootDirectory == null) {
135                     return;
136                 }
137                 List<Path> toLoad = new ArrayList<>();
138                 Path root = defaultModelBuilder.getModelProcessor().locateExistingPom(rootDirectory);
139                 toLoad.add(root);
140                 while (!toLoad.isEmpty()) {
141                     Path pom = toLoad.remove(0);
142                     try {
143                         ModelBuildingRequest gaBuildingRequest =
144                                 new DefaultModelBuildingRequest(request).setModelSource(new FileModelSource(pom));
145                         Model rawModel = defaultModelBuilder.readFileModel(gaBuildingRequest, problems);
146                         for (String module : rawModel.getModules()) {
147                             Path moduleFile = defaultModelBuilder
148                                     .getModelProcessor()
149                                     .locateExistingPom(pom.getParent().resolve(module));
150                             if (moduleFile != null) {
151                                 toLoad.add(moduleFile);
152                             }
153                         }
154                     } catch (ModelBuildingException e) {
155                         // gathered with problem collector
156                     }
157                 }
158             }
159 
160             private Model findRawModel(Path from, Path p) {
161                 if (!Files.isRegularFile(p)) {
162                     throw new IllegalArgumentException("Not a regular file: " + p);
163                 }
164 
165                 if (!addEdge(from, p, problems)) {
166                     return null;
167                 }
168 
169                 DefaultModelBuildingRequest req =
170                         new DefaultModelBuildingRequest(request).setPomPath(p).setModelSource(new FileModelSource(p));
171 
172                 try {
173                     return defaultModelBuilder.readRawModel(req, problems);
174                 } catch (ModelBuildingException e) {
175                     // gathered with problem collector
176                 }
177                 return null;
178             }
179         };
180     }
181 
182     private boolean addEdge(Path from, Path p, DefaultModelProblemCollector problems) {
183         try {
184             dag.addEdge(from.toString(), p.toString());
185             return true;
186         } catch (Graph.CycleDetectedException e) {
187             problems.add(new DefaultModelProblem(
188                     "Cycle detected between models at " + from + " and " + p,
189                     ModelProblem.Severity.FATAL,
190                     null,
191                     null,
192                     0,
193                     0,
194                     null,
195                     e));
196             return false;
197         }
198     }
199 
200     @Override
201     public TransformerContext build() {
202         return context;
203     }
204 
205     public FileModelSource getSource(String groupId, String artifactId) {
206         Set<FileModelSource> sources = mappedSources.get(groupId != null ? groupId + ":" + artifactId : artifactId);
207         if (sources == null) {
208             return null;
209         }
210         return sources.stream()
211                 .reduce((a, b) -> {
212                     throw new IllegalStateException(String.format(
213                             "No unique Source for %s:%s: %s and %s",
214                             groupId, artifactId, a.getLocation(), b.getLocation()));
215                 })
216                 .orElse(null);
217     }
218 
219     public void putSource(String groupId, String artifactId, FileModelSource source) {
220         mappedSources
221                 .computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>())
222                 .add(source);
223         if (groupId != null) {
224             mappedSources.computeIfAbsent(artifactId, k -> new HashSet<>()).add(source);
225         }
226     }
227 }