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.project;
20  
21  import java.nio.file.Files;
22  import java.nio.file.Path;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Map;
27  import java.util.Objects;
28  import java.util.Set;
29  import org.apache.maven.model.Model;
30  
31  /**
32   * Holds all Models that are known to the reactor. This allows the project builder to resolve imported Models from the
33   * reactor when building another project's effective model.
34   *
35   * @author Benjamin Bentmann
36   * @author Robert Scholte
37   */
38  class ReactorModelPool {
39      private final Map<GAKey, Set<Model>> modelsByGa = new HashMap<>();
40  
41      private final Map<Path, Model> modelsByPath = new HashMap<>();
42  
43      /**
44       * Get the model by its GAV or (since 4.0.0) by its GA if there is only one.
45       *
46       * @param groupId never {@code null}
47       * @param artifactId never {@code null}
48       * @param version can be {@code null}
49       * @return the matching model or {@code null}
50       * @throws IllegalStateException if version was null and multiple modules share the same groupId + artifactId
51       */
52      public Model get(String groupId, String artifactId, String version) {
53          return modelsByGa.getOrDefault(new GAKey(groupId, artifactId), Collections.emptySet()).stream()
54                  .filter(m -> version == null || version.equals(getVersion(m)))
55                  .reduce((a, b) -> {
56                      throw new IllegalStateException(
57                              "Multiple modules with key " + a.getGroupId() + ':' + a.getArtifactId());
58                  })
59                  .orElse(null);
60      }
61  
62      /**
63       * Find model by path, useful when location the parent by relativePath
64       *
65       * @param path
66       * @return the matching model or {@code null}
67       * @since 4.0.0
68       */
69      public Model get(Path path) {
70          final Path pomFile;
71          if (Files.isDirectory(path)) {
72              pomFile = path.resolve("pom.xml");
73          } else {
74              pomFile = path;
75          }
76          return modelsByPath.get(pomFile);
77      }
78  
79      private String getVersion(Model model) {
80          String version = model.getVersion();
81          if (version == null && model.getParent() != null) {
82              version = model.getParent().getVersion();
83          }
84          return version;
85      }
86  
87      static class Builder {
88          private ReactorModelPool pool = new ReactorModelPool();
89  
90          Builder put(Path pomFile, Model model) {
91              pool.modelsByPath.put(pomFile, model);
92              pool.modelsByGa
93                      .computeIfAbsent(new GAKey(getGroupId(model), model.getArtifactId()), k -> new HashSet<Model>())
94                      .add(model);
95              return this;
96          }
97  
98          ReactorModelPool build() {
99              return pool;
100         }
101 
102         private static String getGroupId(Model model) {
103             String groupId = model.getGroupId();
104             if (groupId == null && model.getParent() != null) {
105                 groupId = model.getParent().getGroupId();
106             }
107             return groupId;
108         }
109     }
110 
111     private static final class GAKey {
112 
113         private final String groupId;
114 
115         private final String artifactId;
116 
117         private final int hashCode;
118 
119         GAKey(String groupId, String artifactId) {
120             this.groupId = (groupId != null) ? groupId : "";
121             this.artifactId = (artifactId != null) ? artifactId : "";
122 
123             hashCode = Objects.hash(this.groupId, this.artifactId);
124         }
125 
126         @Override
127         public boolean equals(Object obj) {
128             if (this == obj) {
129                 return true;
130             }
131 
132             GAKey that = (GAKey) obj;
133 
134             return artifactId.equals(that.artifactId) && groupId.equals(that.groupId);
135         }
136 
137         @Override
138         public int hashCode() {
139             return hashCode;
140         }
141 
142         @Override
143         public String toString() {
144             StringBuilder buffer = new StringBuilder(128);
145             buffer.append(groupId).append(':').append(artifactId);
146             return buffer.toString();
147         }
148     }
149 }