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.api.services;
20  
21  import java.nio.file.Path;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Optional;
26  import java.util.stream.Stream;
27  
28  import org.apache.maven.api.Language;
29  import org.apache.maven.api.ProducedArtifact;
30  import org.apache.maven.api.Project;
31  import org.apache.maven.api.ProjectScope;
32  import org.apache.maven.api.RemoteRepository;
33  import org.apache.maven.api.Service;
34  import org.apache.maven.api.Session;
35  import org.apache.maven.api.SourceRoot;
36  import org.apache.maven.api.annotations.Experimental;
37  import org.apache.maven.api.annotations.Nonnull;
38  import org.apache.maven.api.annotations.Nullable;
39  
40  /**
41   * Interface to manage the project state and artifacts during the Maven build lifecycle.
42   * This service provides operations to:
43   * <ul>
44   *   <li>Manage project artifacts (main and attached)</li>
45   *   <li>Handle source roots and resources</li>
46   *   <li>Access and modify project properties</li>
47   *   <li>Manage repository configurations</li>
48   *   <li>Handle project forking states</li>
49   * </ul>
50   *
51   * The service maintains the mutable state of projects as they progress through
52   * their build lifecycle, ensuring thread-safety and proper state management.
53   * All implementations must be thread-safe as they may be accessed concurrently
54   * during parallel builds.
55   *
56   * @since 4.0.0
57   * @see org.apache.maven.api.services.ProjectBuilder
58   * @see Project
59   */
60  @Experimental
61  public interface ProjectManager extends Service {
62      /**
63       * Returns the path to the built project artifact file, if the project has been built.
64       * This path is only available after the artifact has been produced during the build lifecycle.
65       *
66       * @param project the project to get the artifact path for
67       * @return an Optional containing the path to the built artifact if available,
68       *         or empty if the artifact hasn't been built yet
69       */
70      @Nonnull
71      Optional<Path> getPath(@Nonnull Project project);
72  
73      /**
74       * Returns an immutable collection of attached artifacts for the given project.
75       * Attached artifacts are secondary artifacts produced during the build (e.g., sources jar,
76       * javadoc jar, test jars). These artifacts are created and attached during specific
77       * lifecycle phases, so the collection contents depend on the build phase when this method
78       * is called.
79       *
80       * @param project the project to get attached artifacts for
81       * @return an immutable collection of attached artifacts, may be empty if no artifacts
82       *         have been attached yet
83       * @throws IllegalArgumentException if the project is null
84       * @see #getAllArtifacts(Project)
85       */
86      @Nonnull
87      Collection<ProducedArtifact> getAttachedArtifacts(@Nonnull Project project);
88  
89      /**
90       * Returns project's all artifacts as an immutable ordered collection. The collection contains:
91       * <ul>
92       *   <li>The project's artifacts ({@link Project#getArtifacts()}):
93       *     <ul>
94       *       <li>The POM artifact (always present)</li>
95       *       <li>The main project artifact (if applicable based on packaging)</li>
96       *     </ul>
97       *   </li>
98       *   <li>All attached artifacts in the order they were attached</li>
99       * </ul>
100      * The contents depend on the current lifecycle phase when this method is called, as artifacts
101      * are typically attached during specific phases (e.g., sources jar during package phase).
102      *
103      * @param project the project to get artifacts for
104      * @return an immutable ordered collection of all project artifacts
105      * @see #getAttachedArtifacts(Project)
106      */
107     @Nonnull
108     Collection<ProducedArtifact> getAllArtifacts(@Nonnull Project project);
109 
110     /**
111      * Attaches an artifact to the project using the given file path. The artifact type will be
112      * determined from the file extension. This method is thread-safe and ensures proper
113      * synchronization of the project's artifact state.
114      *
115      * @param session the current build session
116      * @param project the project to attach the artifact to
117      * @param path the path to the artifact file
118      */
119     default void attachArtifact(@Nonnull Session session, @Nonnull Project project, @Nonnull Path path) {
120         String name = path.getFileName().toString();
121         int dot = name.lastIndexOf('.');
122         String ext = dot >= 1 ? name.substring(dot + 1) : "";
123         ProducedArtifact artifact = session.createProducedArtifact(
124                 project.getGroupId(), project.getArtifactId(), project.getVersion(), ext);
125         attachArtifact(project, artifact, path);
126     }
127 
128     /**
129      * Attaches an artifact to the project with an explicitly specified type.
130      *
131      * @param session the current build session
132      * @param project the project to attach the artifact to
133      * @param type the type of the artifact (e.g., "jar", "war", "sources")
134      * @param path the path to the artifact file
135      * @see org.apache.maven.api.Type
136      */
137     default void attachArtifact(
138             @Nonnull Session session, @Nonnull Project project, @Nonnull String type, @Nonnull Path path) {
139         ProducedArtifact artifact = session.createProducedArtifact(
140                 project.getGroupId(), project.getArtifactId(), project.getVersion(), null, null, type);
141         attachArtifact(project, artifact, path);
142     }
143 
144     /**
145      * Attaches a produced artifact to the project at the specified path. This is the base method
146      * that the other attachArtifact methods delegate to.
147      *
148      * @param project the project to attach the artifact to
149      * @param artifact the produced artifact to attach
150      * @param path the path to the artifact file
151      */
152     void attachArtifact(@Nonnull Project project, @Nonnull ProducedArtifact artifact, @Nonnull Path path);
153 
154     /**
155      * {@return all source root directories}, including the disabled ones, for all languages and scopes.
156      * For listing only the {@linkplain SourceRoot#enabled() enabled} source roots,
157      * the following code can be used:
158      *
159      * <pre>{@literal
160      * List<SourceRoot> enabledRoots = project.getSourceRoots()
161      *         .stream().filter(SourceRoot::enabled).toList();
162      * }</pre>
163      *
164      * The iteration order is the order in which the sources are declared in the POM file.
165      *
166      * @param project the project for which to get the source roots
167      */
168     @Nonnull
169     Collection<SourceRoot> getSourceRoots(@Nonnull Project project);
170 
171     /**
172      * {@return all enabled sources that provide files in the given language for the given scope}.
173      * If the given scope is {@code null}, then this method returns the enabled sources for all scopes.
174      * If the given language is {@code null}, then this method returns the enabled sources for all languages.
175      * An arbitrary number of source roots may exist for the same scope and language.
176      * It may be, for example, the case of a multi-versions project.
177      * The iteration order is the order in which the sources are declared in the POM file.
178      *
179      * @param project the project for which to get the enabled source roots
180      * @param scope the scope of the sources to return, or {@code null} for all scopes
181      * @param language the language of the sources to return, or {@code null} for all languages
182      */
183     @Nonnull
184     Stream<SourceRoot> getEnabledSourceRoots(
185             @Nonnull Project project, @Nullable ProjectScope scope, @Nullable Language language);
186 
187     /**
188      * Adds the given source to the given project.
189      * If a source already exists for the given scope, language and directory,
190      * then the behavior depends on the {@code ProjectManager} implementation.
191      * It may do nothing or thrown {@linkplain IllegalArgumentException}.
192      *
193      * @param project the project to update
194      * @param source the source to add
195      * @throws IllegalArgumentException if this project manager rejects the given source because of conflict
196      *
197      * @see #getSourceRoots(Project)
198      */
199     void addSourceRoot(@Nonnull Project project, @Nonnull SourceRoot source);
200 
201     /**
202      * Resolves and adds the given directory as a source with the given scope and language.
203      * First, this method resolves the given root against the project base directory, then normalizes the path.
204      * If no source already exists for the same scope, language and normalized directory,
205      * these arguments are added as a new {@link SourceRoot} element.
206      * Otherwise (i.e., in case of potential conflict), the behavior depends on the {@code ProjectManager}.
207      * The default implementation does nothing in the latter case.
208      *
209      * @param project the project to update
210      * @param scope scope (main or test) of the directory to add
211      * @param language language of the files contained in the directory to add
212      * @param directory the directory to add if not already present in the source
213      *
214      * @see #getEnabledSourceRoots(Project, ProjectScope, Language)
215      */
216     void addSourceRoot(
217             @Nonnull Project project, @Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull Path directory);
218 
219     /**
220      * Returns an immutable list of project remote repositories (directly specified or inherited).
221      * The repositories are ordered by declaration order, with inherited repositories appearing
222      * after directly specified ones.
223      *
224      * @param project the project
225      * @return ordered list of remote repositories
226      */
227     @Nonnull
228     List<RemoteRepository> getRemoteProjectRepositories(@Nonnull Project project);
229 
230     /**
231      * Returns an immutable list of project plugin remote repositories (directly specified or inherited).
232      * The repositories are ordered by declaration order, with inherited repositories appearing
233      * after directly specified ones.
234      *
235      * @param project the project
236      * @return ordered list of remote repositories
237      */
238     @Nonnull
239     List<RemoteRepository> getRemotePluginRepositories(@Nonnull Project project);
240 
241     /**
242      * {@return an immutable map of the project properties}.
243      *
244      * @param project the project for which to get the properties
245      *
246      * @see #setProperty(Project, String, String)
247      */
248     @Nonnull
249     Map<String, String> getProperties(@Nonnull Project project);
250 
251     /**
252      * Set a given project property. Properties set through this method are only valid
253      * for the current build session and do not modify the underlying project model.
254      *
255      * @param project the project to modify
256      * @param key they property's key
257      * @param value the value or {@code null} to unset the property
258      */
259     void setProperty(@Nonnull Project project, @Nonnull String key, @Nullable String value);
260 
261     /**
262      * Returns the original project being built when the input project is a forked project.
263      * During certain lifecycle phases, particularly for aggregator mojos, Maven may create
264      * a forked project (a copy of the original project) to execute a subset of the lifecycle.
265      * This method allows retrieving the original project that initiated the build.
266      *
267      * @param project the potentially forked project
268      * @return an Optional containing the original project if the input is a forked project,
269      *         or an empty Optional if the input is already the original project
270      * @throws IllegalArgumentException if the project is null
271      */
272     @Nonnull
273     Optional<Project> getExecutionProject(@Nonnull Project project);
274 }