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.io.File;
22  import java.io.IOException;
23  import java.io.Writer;
24  import java.nio.file.Path;
25  import java.util.AbstractSequentialList;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.LinkedHashMap;
31  import java.util.LinkedHashSet;
32  import java.util.List;
33  import java.util.ListIterator;
34  import java.util.Map;
35  import java.util.Objects;
36  import java.util.Properties;
37  import java.util.Set;
38  import java.util.function.Predicate;
39  import java.util.stream.Stream;
40  
41  import org.apache.maven.RepositoryUtils;
42  import org.apache.maven.api.Language;
43  import org.apache.maven.api.ProjectScope;
44  import org.apache.maven.api.SourceRoot;
45  import org.apache.maven.api.annotations.Nonnull;
46  import org.apache.maven.artifact.Artifact;
47  import org.apache.maven.artifact.ArtifactUtils;
48  import org.apache.maven.artifact.DependencyResolutionRequiredException;
49  import org.apache.maven.artifact.factory.ArtifactFactory;
50  import org.apache.maven.artifact.handler.ArtifactHandler;
51  import org.apache.maven.artifact.repository.ArtifactRepository;
52  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
53  import org.apache.maven.impl.DefaultSourceRoot;
54  import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory;
55  import org.apache.maven.model.Build;
56  import org.apache.maven.model.CiManagement;
57  import org.apache.maven.model.Contributor;
58  import org.apache.maven.model.Dependency;
59  import org.apache.maven.model.DependencyManagement;
60  import org.apache.maven.model.Developer;
61  import org.apache.maven.model.DistributionManagement;
62  import org.apache.maven.model.Extension;
63  import org.apache.maven.model.IssueManagement;
64  import org.apache.maven.model.License;
65  import org.apache.maven.model.MailingList;
66  import org.apache.maven.model.Model;
67  import org.apache.maven.model.Organization;
68  import org.apache.maven.model.Plugin;
69  import org.apache.maven.model.PluginExecution;
70  import org.apache.maven.model.PluginManagement;
71  import org.apache.maven.model.Prerequisites;
72  import org.apache.maven.model.Profile;
73  import org.apache.maven.model.ReportPlugin;
74  import org.apache.maven.model.ReportSet;
75  import org.apache.maven.model.Reporting;
76  import org.apache.maven.model.Repository;
77  import org.apache.maven.model.Resource;
78  import org.apache.maven.model.Scm;
79  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
80  import org.apache.maven.model.root.RootLocator;
81  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
82  import org.codehaus.plexus.classworlds.realm.ClassRealm;
83  import org.codehaus.plexus.util.xml.Xpp3Dom;
84  import org.eclipse.aether.graph.DependencyFilter;
85  import org.eclipse.aether.repository.RemoteRepository;
86  import org.slf4j.Logger;
87  import org.slf4j.LoggerFactory;
88  
89  /**
90   * The concern of the project is provide runtime values based on the model.
91   * <p>
92   * The values in the model remain untouched but during the process of building a project notions like inheritance and
93   * interpolation can be added. This allows to have an entity which is useful in a runtime while preserving the model so
94   * that it can be marshalled and unmarshalled without being tainted by runtime requirements.
95   * </p>
96   * <p>
97   * With changes during 3.2.2 release MavenProject is closer to being immutable after construction with the removal of
98   * all components from this class, and the upfront construction taken care of entirely by the {@link ProjectBuilder}.
99   * There is still the issue of having to run the lifecycle in order to find all the compile source roots and resource
100  * directories but I hope to take care of this during the Maven 4.0 release (jvz).
101  * </p>
102  */
103 public class MavenProject implements Cloneable {
104 
105     private static final Logger LOGGER = LoggerFactory.getLogger(MavenProject.class);
106 
107     public static final String EMPTY_PROJECT_GROUP_ID = "unknown";
108 
109     public static final String EMPTY_PROJECT_ARTIFACT_ID = "empty-project";
110 
111     public static final String EMPTY_PROJECT_VERSION = "0";
112 
113     private Model model;
114 
115     private MavenProject parent;
116 
117     private File file;
118 
119     private File basedir;
120 
121     private Path rootDirectory;
122 
123     private Set<Artifact> resolvedArtifacts;
124 
125     private ArtifactFilter artifactFilter;
126 
127     private Set<Artifact> artifacts;
128 
129     private Artifact parentArtifact;
130 
131     private Set<Artifact> pluginArtifacts;
132 
133     @Deprecated
134     private List<ArtifactRepository> remoteArtifactRepositories;
135 
136     @Deprecated
137     private List<ArtifactRepository> pluginArtifactRepositories;
138 
139     private List<RemoteRepository> remoteProjectRepositories;
140 
141     private List<RemoteRepository> remotePluginRepositories;
142 
143     private List<Artifact> attachedArtifacts = new ArrayList<>();
144 
145     private MavenProject executionProject;
146 
147     private List<MavenProject> collectedProjects;
148 
149     /**
150      * All sources of this project, in the order they were added.
151      */
152     Set<SourceRoot> sources = new LinkedHashSet<>();
153 
154     @Deprecated
155     private ArtifactRepository releaseArtifactRepository;
156 
157     @Deprecated
158     private ArtifactRepository snapshotArtifactRepository;
159 
160     private List<Profile> activeProfiles = new ArrayList<>();
161 
162     private Map<String, List<String>> injectedProfileIds = new LinkedHashMap<>();
163 
164     @Deprecated
165     private Set<Artifact> dependencyArtifacts;
166 
167     private Artifact artifact;
168 
169     // calculated.
170     private Map<String, Artifact> artifactMap;
171 
172     private Model originalModel;
173 
174     private Map<String, Artifact> pluginArtifactMap;
175 
176     @Deprecated
177     private Set<Artifact> reportArtifacts;
178 
179     @Deprecated
180     private Map<String, Artifact> reportArtifactMap;
181 
182     @Deprecated
183     private Set<Artifact> extensionArtifacts;
184 
185     @Deprecated
186     private Map<String, Artifact> extensionArtifactMap;
187 
188     private Map<String, Artifact> managedVersionMap;
189 
190     private Map<String, MavenProject> projectReferences = new HashMap<>();
191 
192     private boolean executionRoot;
193 
194     private File parentFile;
195 
196     private Map<String, Object> context;
197 
198     private ClassRealm classRealm;
199 
200     private DependencyFilter extensionDependencyFilter;
201 
202     private final Set<String> lifecyclePhases = Collections.synchronizedSet(new LinkedHashSet<>());
203 
204     public MavenProject() {
205         Model model = new Model();
206 
207         model.setGroupId(EMPTY_PROJECT_GROUP_ID);
208         model.setArtifactId(EMPTY_PROJECT_ARTIFACT_ID);
209         model.setVersion(EMPTY_PROJECT_VERSION);
210 
211         setModel(model);
212     }
213 
214     public MavenProject(org.apache.maven.api.model.Model model) {
215         this(new Model(model));
216     }
217 
218     public MavenProject(Model model) {
219         setModel(model);
220     }
221 
222     public MavenProject(MavenProject project) {
223         deepCopy(project);
224     }
225 
226     public File getParentFile() {
227         return parentFile;
228     }
229 
230     public void setParentFile(File parentFile) {
231         this.parentFile = parentFile;
232     }
233 
234     // ----------------------------------------------------------------------
235     // Accessors
236     // ----------------------------------------------------------------------
237 
238     public Artifact getArtifact() {
239         return artifact;
240     }
241 
242     public void setArtifact(Artifact artifact) {
243         this.artifact = artifact;
244     }
245 
246     // TODO I would like to get rid of this. jvz.
247     public Model getModel() {
248         return model;
249     }
250 
251     /**
252      * Returns the project corresponding to a declared parent.
253      *
254      * @return the parent, or null if no parent is declared or there was an error building it
255      */
256     public MavenProject getParent() {
257         return parent;
258     }
259 
260     public void setParent(MavenProject parent) {
261         this.parent = parent;
262     }
263 
264     public boolean hasParent() {
265         return getParent() != null;
266     }
267 
268     public File getFile() {
269         return file;
270     }
271 
272     public void setFile(File file) {
273         this.file = file;
274         this.basedir = file != null ? file.getParentFile() : null;
275     }
276 
277     /**
278      * Sets project {@code file} without changing project {@code basedir}.
279      *
280      * @since 3.2.4
281      */
282     public void setPomFile(File file) {
283         this.file = file;
284     }
285 
286     /**
287      * @deprecated Replaced by {@link #getBaseDirectory()} for migrating from {@code File} to {@code Path}.
288      */
289     @Deprecated(since = "4.0.0")
290     public File getBasedir() {
291         return basedir;
292     }
293 
294     /**
295      * {@return the base directory of this project}.
296      * All source files are relative to this directory, unless they were specified as absolute paths.
297      *
298      * @since 4.0.0
299      */
300     public Path getBaseDirectory() {
301         return getBasedir().toPath();
302     }
303 
304     public void setDependencies(List<Dependency> dependencies) {
305         getModel().setDependencies(dependencies);
306     }
307 
308     public List<Dependency> getDependencies() {
309         return getModel().getDependencies();
310     }
311 
312     public DependencyManagement getDependencyManagement() {
313         return getModel().getDependencyManagement();
314     }
315 
316     // ----------------------------------------------------------------------
317     // Test and compile source roots.
318     // ----------------------------------------------------------------------
319 
320     /**
321      * Adds the given source if not already present.
322      *
323      * @param source the source to add
324      *
325      * @see #getSourceRoots()
326      *
327      * @since 4.0.0
328      */
329     public void addSourceRoot(SourceRoot source) {
330         sources.add(source);
331     }
332 
333     /**
334      * Resolves and adds the given directory as a source with the given scope and language.
335      * First, this method resolves the given root against the {@linkplain #getBaseDirectory() base directory},
336      * then normalizes the path. If a source already exists for the same scope, language and normalized directory,
337      * this method does nothing. Otherwise, the normalized directory is added as a new {@link SourceRoot} element.
338      *
339      * @param scope scope (main or test) of the directory to add
340      * @param language language of the files contained in the directory to add
341      * @param directory the directory to add if not already present in the source
342      *
343      * @see #getEnabledSourceRoots(ProjectScope, Language)
344      *
345      * @since 4.0.0
346      */
347     public void addSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull Path directory) {
348         directory = getBaseDirectory()
349                 .resolve(Objects.requireNonNull(directory, "directory cannot be null"))
350                 .normalize();
351         addSourceRoot(new DefaultSourceRoot(scope, language, directory));
352     }
353 
354     /**
355      * Resolves and adds the given directory as a source with the given scope and language.
356      * If the given directory is null, blank or already in the sources, then this method does nothing.
357      * Otherwise, the directory is converted to a path, resolved, normalized and finally added as a new
358      * {@link SourceRoot} element if no source exists for these scope, language and normalized directory.
359      *
360      * @param scope scope (main or test) of the directory to add
361      * @param language language of the files contained in the directory to add
362      * @param directory the directory to add if not already present in the source, or null
363      *
364      * @since 4.0.0
365      */
366     public void addSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull String directory) {
367         directory =
368                 Objects.requireNonNull(directory, "directory cannot be null").trim();
369         if (!directory.isBlank()) {
370             Path path = getBaseDirectory().resolve(directory).normalize();
371             addSourceRoot(scope, language, path);
372         }
373     }
374 
375     /**
376      * Removes a source root from the project.
377      *
378      * @param scope the scope of the source root
379      * @param language the language of the source root
380      * @param directory the directory of the source root
381      */
382     public void removeSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull Path directory) {
383         Path path = getBaseDirectory()
384                 .resolve(Objects.requireNonNull(directory, "directory cannot be null"))
385                 .normalize();
386         sources.removeIf(source -> source.scope() == scope
387                 && source.language() == language
388                 && source.directory().equals(path));
389     }
390 
391     /**
392      * Removes a source root from the project.
393      *
394      * @param scope the scope of the source root
395      * @param language the language of the source root
396      * @param directory the directory of the source root
397      */
398     public void removeSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull String directory) {
399         directory =
400                 Objects.requireNonNull(directory, "directory cannot be null").trim();
401         if (!directory.isBlank()) {
402             removeSourceRoot(scope, language, Path.of(directory));
403         }
404     }
405 
406     /**
407      * @deprecated Replaced by {@code addSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path)}.
408      */
409     @Deprecated(since = "4.0.0")
410     public void addCompileSourceRoot(String path) {
411         addSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path);
412     }
413 
414     /**
415      * @deprecated Replaced by {@code removeSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path)}.
416      */
417     @Deprecated(since = "4.0.0")
418     public void removeCompileSourceRoot(String path) {
419         removeSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path);
420     }
421 
422     /**
423      * @deprecated Replaced by {@code addSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path)}.
424      */
425     @Deprecated(since = "4.0.0")
426     public void addTestCompileSourceRoot(String path) {
427         addSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path);
428     }
429 
430     /**
431      * @deprecated Replaced by {@code removeSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path)}.
432      */
433     public void removeTestCompileSourceRoot(String path) {
434         removeSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path);
435     }
436     /**
437      * {@return all source root directories, including the disabled ones, for all languages and scopes}.
438      * The iteration order is the order in which the sources are declared in the POM file.
439      * The returned collection is unmodifiable.
440      *
441      * @see #addSourceRoot(SourceRoot)
442      */
443     public Collection<SourceRoot> getSourceRoots() {
444         return Collections.unmodifiableCollection(sources);
445     }
446 
447     /**
448      * {@return all enabled sources that provide files in the given language for the given scope}.
449      * If the given scope is {@code null}, then this method returns the enabled sources for all scopes.
450      * If the given language is {@code null}, then this method returns the enabled sources for all languages.
451      * The iteration order is the order in which the sources are declared in the POM file.
452      *
453      * @param scope the scope of the sources to return, or {@code null} for all scopes
454      * @param language the language of the sources to return, or {@code null} for all languages
455      *
456      * @see #addSourceRoot(ProjectScope, Language, Path)
457      *
458      * @since 4.0.0
459      */
460     public Stream<SourceRoot> getEnabledSourceRoots(ProjectScope scope, Language language) {
461         Stream<SourceRoot> stream = sources.stream().filter(SourceRoot::enabled);
462         if (scope != null) {
463             stream = stream.filter(source -> scope.equals(source.scope()));
464         }
465         if (language != null) {
466             stream = stream.filter(source -> language.equals(source.language()));
467         }
468         return stream;
469     }
470 
471     /**
472      * Returns a list of paths for the given scope.
473      *
474      * @deprecated Used only for the implementation of deprecated methods.
475      */
476     @Deprecated
477     private List<String> getSourceRootDirs(ProjectScope scope, Language language) {
478         return getEnabledSourceRoots(scope, language)
479                 .map((source) -> source.directory().toString())
480                 .toList();
481     }
482 
483     /**
484      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)}.
485      */
486     @Deprecated(since = "4.0.0")
487     public List<String> getCompileSourceRoots() {
488         return getSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY);
489     }
490 
491     /**
492      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)}.
493      */
494     @Deprecated(since = "4.0.0")
495     public List<String> getTestCompileSourceRoots() {
496         return getSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY);
497     }
498 
499     // TODO let the scope handler deal with this
500     private static boolean isCompilePathElement(final String scope) {
501         return Artifact.SCOPE_COMPILE.equals(scope)
502                 || Artifact.SCOPE_PROVIDED.equals(scope)
503                 || Artifact.SCOPE_SYSTEM.equals(scope);
504     }
505 
506     // TODO let the scope handler deal with this
507     private static boolean isRuntimePathElement(final String scope) {
508         return Artifact.SCOPE_COMPILE.equals(scope) || Artifact.SCOPE_RUNTIME.equals(scope);
509     }
510 
511     // TODO let the scope handler deal with this
512     private static boolean isTestPathElement(final String scope) {
513         return true;
514     }
515 
516     /**
517      * Returns a filtered list of class path elements. This method is invoked when the caller
518      * requested that all dependencies are placed on the class path, with no module path element.
519      *
520      * @param scopeFilter a filter returning {@code true} for the artifact scopes to accept
521      * @param includeTestDir whether to include the test directory in the classpath elements
522      * @return paths of all artifacts placed on the classpath
523      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
524      */
525     private List<String> getClasspathElements(final Predicate<String> scopeFilter, final boolean includeTestDir)
526             throws DependencyResolutionRequiredException {
527         final List<String> list = new ArrayList<>(getArtifacts().size() + 2);
528         if (includeTestDir) {
529             String d = getBuild().getTestOutputDirectory();
530             if (d != null) {
531                 list.add(d);
532             }
533         }
534         String d = getBuild().getOutputDirectory();
535         if (d != null) {
536             list.add(d);
537         }
538         for (Artifact a : getArtifacts()) {
539             final File f = a.getFile();
540             if (f != null && scopeFilter.test(a.getScope())) {
541                 final ArtifactHandler h = a.getArtifactHandler();
542                 if (h.isAddedToClasspath()) {
543                     list.add(f.getPath());
544                 }
545             }
546         }
547         return list;
548     }
549 
550     /**
551      * Returns the elements placed on the classpath for compilation.
552      * This method can be invoked when the caller does not support module-path.
553      *
554      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
555      *
556      * @deprecated This method is unreliable because it does not consider other dependency properties.
557      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
558      */
559     @Deprecated
560     public List<String> getCompileClasspathElements() throws DependencyResolutionRequiredException {
561         return getClasspathElements(MavenProject::isCompilePathElement, false);
562     }
563 
564     /**
565      * Returns the elements placed on the classpath for tests.
566      * This method can be invoked when the caller does not support module-path.
567      *
568      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
569      *
570      * @deprecated This method is unreliable because it does not consider other dependency properties.
571      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
572      */
573     @Deprecated
574     public List<String> getTestClasspathElements() throws DependencyResolutionRequiredException {
575         return getClasspathElements(MavenProject::isTestPathElement, true);
576     }
577 
578     /**
579      * Returns the elements placed on the classpath for runtime.
580      * This method can be invoked when the caller does not support module-path.
581      *
582      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
583      *
584      * @deprecated This method is unreliable because it does not consider other dependency properties.
585      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
586      */
587     @Deprecated
588     public List<String> getRuntimeClasspathElements() throws DependencyResolutionRequiredException {
589         return getClasspathElements(MavenProject::isRuntimePathElement, false);
590     }
591 
592     // ----------------------------------------------------------------------
593     // Delegate to the model
594     // ----------------------------------------------------------------------
595 
596     public void setModelVersion(String pomVersion) {
597         getModel().setModelVersion(pomVersion);
598     }
599 
600     public String getModelVersion() {
601         return getModel().getModelVersion();
602     }
603 
604     public String getId() {
605         return getModel().getId();
606     }
607 
608     public void setGroupId(String groupId) {
609         getModel().setGroupId(groupId);
610     }
611 
612     public String getGroupId() {
613         String groupId = getModel().getGroupId();
614 
615         if ((groupId == null) && (getModel().getParent() != null)) {
616             groupId = getModel().getParent().getGroupId();
617         }
618 
619         return groupId;
620     }
621 
622     public void setArtifactId(String artifactId) {
623         getModel().setArtifactId(artifactId);
624     }
625 
626     public String getArtifactId() {
627         return getModel().getArtifactId();
628     }
629 
630     public void setName(String name) {
631         getModel().setName(name);
632     }
633 
634     public String getName() {
635         if (getModel().getName() != null) {
636             return getModel().getName();
637         } else {
638             return getArtifactId();
639         }
640     }
641 
642     public void setVersion(String version) {
643         getModel().setVersion(version);
644     }
645 
646     public String getVersion() {
647         String version = getModel().getVersion();
648 
649         if ((version == null) && (getModel().getParent() != null)) {
650             version = getModel().getParent().getVersion();
651         }
652 
653         return version;
654     }
655 
656     public String getPackaging() {
657         return getModel().getPackaging();
658     }
659 
660     public void setPackaging(String packaging) {
661         getModel().setPackaging(packaging);
662     }
663 
664     public void setInceptionYear(String inceptionYear) {
665         getModel().setInceptionYear(inceptionYear);
666     }
667 
668     public String getInceptionYear() {
669         return getModel().getInceptionYear();
670     }
671 
672     public void setUrl(String url) {
673         getModel().setUrl(url);
674     }
675 
676     public String getUrl() {
677         return getModel().getUrl();
678     }
679 
680     public Prerequisites getPrerequisites() {
681         return getModel().getPrerequisites();
682     }
683 
684     public void setIssueManagement(IssueManagement issueManagement) {
685         getModel().setIssueManagement(issueManagement);
686     }
687 
688     public CiManagement getCiManagement() {
689         return getModel().getCiManagement();
690     }
691 
692     public void setCiManagement(CiManagement ciManagement) {
693         getModel().setCiManagement(ciManagement);
694     }
695 
696     public IssueManagement getIssueManagement() {
697         return getModel().getIssueManagement();
698     }
699 
700     public void setDistributionManagement(DistributionManagement distributionManagement) {
701         getModel().setDistributionManagement(distributionManagement);
702     }
703 
704     public DistributionManagement getDistributionManagement() {
705         return getModel().getDistributionManagement();
706     }
707 
708     public void setDescription(String description) {
709         getModel().setDescription(description);
710     }
711 
712     public String getDescription() {
713         return getModel().getDescription();
714     }
715 
716     public void setOrganization(Organization organization) {
717         getModel().setOrganization(organization);
718     }
719 
720     public Organization getOrganization() {
721         return getModel().getOrganization();
722     }
723 
724     public void setScm(Scm scm) {
725         getModel().setScm(scm);
726     }
727 
728     public Scm getScm() {
729         return getModel().getScm();
730     }
731 
732     public void setMailingLists(List<MailingList> mailingLists) {
733         getModel().setMailingLists(mailingLists);
734     }
735 
736     public List<MailingList> getMailingLists() {
737         return getModel().getMailingLists();
738     }
739 
740     public void addMailingList(MailingList mailingList) {
741         getModel().addMailingList(mailingList);
742     }
743 
744     public void setDevelopers(List<Developer> developers) {
745         getModel().setDevelopers(developers);
746     }
747 
748     public List<Developer> getDevelopers() {
749         return getModel().getDevelopers();
750     }
751 
752     public void addDeveloper(Developer developer) {
753         getModel().addDeveloper(developer);
754     }
755 
756     public void setContributors(List<Contributor> contributors) {
757         getModel().setContributors(contributors);
758     }
759 
760     public List<Contributor> getContributors() {
761         return getModel().getContributors();
762     }
763 
764     public void addContributor(Contributor contributor) {
765         getModel().addContributor(contributor);
766     }
767 
768     public void setBuild(Build build) {
769         getModel().setBuild(build);
770     }
771 
772     public Build getBuild() {
773         return getModelBuild();
774     }
775 
776     /**
777      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)}.
778      */
779     @Deprecated(since = "4.0.0")
780     public List<Resource> getResources() {
781         return getResources(ProjectScope.MAIN);
782     }
783 
784     /**
785      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)}.
786      */
787     @Deprecated(since = "4.0.0")
788     public List<Resource> getTestResources() {
789         return getResources(ProjectScope.TEST);
790     }
791 
792     private List<Resource> getResources(final ProjectScope scope) {
793         return new AbstractSequentialList<>() {
794             private Stream<SourceRoot> sources() {
795                 return getEnabledSourceRoots(scope, Language.RESOURCES);
796             }
797 
798             @Override
799             public ListIterator<Resource> listIterator(int index) {
800                 return sources()
801                         .map(sourceRoot -> toConnectedResource(sourceRoot, scope))
802                         .toList()
803                         .listIterator(index);
804             }
805 
806             @Override
807             public int size() {
808                 return Math.toIntExact(sources().count());
809             }
810 
811             @Override
812             public boolean isEmpty() {
813                 return sources().findAny().isEmpty();
814             }
815 
816             @Override
817             public boolean add(Resource resource) {
818                 addResource(scope, resource);
819                 return true;
820             }
821         };
822     }
823 
824     private static Resource toResource(SourceRoot sourceRoot) {
825         return new Resource(org.apache.maven.api.model.Resource.newBuilder()
826                 .directory(sourceRoot.directory().toString())
827                 .includes(sourceRoot.includes())
828                 .excludes(sourceRoot.excludes())
829                 .filtering(Boolean.toString(sourceRoot.stringFiltering()))
830                 .targetPath(sourceRoot.targetPath().map(Path::toString).orElse(null))
831                 .build());
832     }
833 
834     private Resource toConnectedResource(SourceRoot sourceRoot, ProjectScope scope) {
835         return new ConnectedResource(sourceRoot, scope, this);
836     }
837 
838     private void addResource(ProjectScope scope, Resource resource) {
839         addSourceRoot(new DefaultSourceRoot(getBaseDirectory(), scope, resource.getDelegate()));
840         // Also update the model's Build to maintain compatibility with code that
841         // accesses resources via project.getBuild().getResources()
842         if (scope == ProjectScope.MAIN) {
843             getModelBuild().addResource(resource);
844         } else {
845             getModelBuild().addTestResource(resource);
846         }
847     }
848 
849     /**
850      * Syncs {@code Build.resources/testResources} from the {@code sources} set
851      * for Maven 3 plugin compatibility (e.g. when resources come from {@code <sources>}).
852      */
853     void syncBuildResources() {
854         getModelBuild().setResources(new java.util.ArrayList<>(getResources()));
855         getModelBuild().setTestResources(new java.util.ArrayList<>(getTestResources()));
856     }
857 
858     /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
859     @Deprecated(since = "4.0.0")
860     public void addResource(Resource resource) {
861         addResource(ProjectScope.MAIN, resource);
862     }
863 
864     /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
865     @Deprecated(since = "4.0.0")
866     public void addTestResource(Resource testResource) {
867         addResource(ProjectScope.TEST, testResource);
868     }
869 
870     public void setLicenses(List<License> licenses) {
871         getModel().setLicenses(licenses);
872     }
873 
874     public List<License> getLicenses() {
875         return getModel().getLicenses();
876     }
877 
878     public void addLicense(License license) {
879         getModel().addLicense(license);
880     }
881 
882     public void setArtifacts(Set<Artifact> artifacts) {
883         this.artifacts = artifacts;
884 
885         // flush the calculated artifactMap
886         artifactMap = null;
887     }
888 
889     /**
890      * All dependencies that this project has, including transitive ones. Contents are lazily populated, so depending on
891      * what phases have run dependencies in some scopes won't be included. e.g. if only compile phase has run,
892      * dependencies with scope test won't be included.
893      *
894      * @return {@link Set} &lt; {@link Artifact} &gt;
895      * @see #getDependencyArtifacts() to get only direct dependencies
896      */
897     public Set<Artifact> getArtifacts() {
898         if (artifacts == null) {
899             if (artifactFilter == null || resolvedArtifacts == null) {
900                 artifacts = new LinkedHashSet<>();
901             } else {
902                 artifacts = new LinkedHashSet<>(resolvedArtifacts.size() * 2);
903                 for (Artifact artifact : resolvedArtifacts) {
904                     if (artifactFilter.include(artifact)) {
905                         artifacts.add(artifact);
906                     }
907                 }
908             }
909         }
910         return artifacts;
911     }
912 
913     public Map<String, Artifact> getArtifactMap() {
914         if (artifactMap == null) {
915             artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
916         }
917         return artifactMap;
918     }
919 
920     public void setPluginArtifacts(Set<Artifact> pluginArtifacts) {
921         this.pluginArtifacts = pluginArtifacts;
922 
923         this.pluginArtifactMap = null;
924     }
925 
926     public Set<Artifact> getPluginArtifacts() {
927         return pluginArtifacts;
928     }
929 
930     public Map<String, Artifact> getPluginArtifactMap() {
931         if (pluginArtifactMap == null) {
932             pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getPluginArtifacts());
933         }
934 
935         return pluginArtifactMap;
936     }
937 
938     public void setParentArtifact(Artifact parentArtifact) {
939         this.parentArtifact = parentArtifact;
940     }
941 
942     public Artifact getParentArtifact() {
943         return parentArtifact;
944     }
945 
946     public List<Repository> getRepositories() {
947         return getModel().getRepositories();
948     }
949 
950     // ----------------------------------------------------------------------
951     // Plugins
952     // ----------------------------------------------------------------------
953 
954     public List<Plugin> getBuildPlugins() {
955         if (getModel().getBuild() == null) {
956             return Collections.emptyList();
957         }
958         return Collections.unmodifiableList(getModel().getBuild().getPlugins());
959     }
960 
961     public List<String> getModules() {
962         if (!getModel().getDelegate().getSubprojects().isEmpty()) {
963             return getModel().getDelegate().getSubprojects();
964         }
965         return getModel().getModules();
966     }
967 
968     public PluginManagement getPluginManagement() {
969         PluginManagement pluginMgmt = null;
970 
971         Build build = getModel().getBuild();
972         if (build != null) {
973             pluginMgmt = build.getPluginManagement();
974         }
975 
976         return pluginMgmt;
977     }
978 
979     private Build getModelBuild() {
980         Build build = getModel().getBuild();
981 
982         if (build == null) {
983             build = new Build();
984 
985             getModel().setBuild(build);
986         }
987 
988         return build;
989     }
990 
991     @Deprecated
992     public void setRemoteArtifactRepositories(List<ArtifactRepository> remoteArtifactRepositories) {
993         this.remoteArtifactRepositories = remoteArtifactRepositories;
994         this.remoteProjectRepositories = RepositoryUtils.toRepos(getRemoteArtifactRepositories());
995     }
996 
997     @Deprecated
998     public List<ArtifactRepository> getRemoteArtifactRepositories() {
999         if (remoteArtifactRepositories == null) {
1000             remoteArtifactRepositories = new ArrayList<>();
1001         }
1002 
1003         return remoteArtifactRepositories;
1004     }
1005 
1006     @Deprecated
1007     public void setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
1008         this.pluginArtifactRepositories = pluginArtifactRepositories;
1009         this.remotePluginRepositories = RepositoryUtils.toRepos(getPluginArtifactRepositories());
1010     }
1011 
1012     /**
1013      * @return a list of ArtifactRepository objects constructed from the Repository objects returned by
1014      *         getPluginRepositories.
1015      */
1016     @Deprecated
1017     public List<ArtifactRepository> getPluginArtifactRepositories() {
1018         if (pluginArtifactRepositories == null) {
1019             pluginArtifactRepositories = new ArrayList<>();
1020         }
1021 
1022         return pluginArtifactRepositories;
1023     }
1024 
1025     @Deprecated
1026     public ArtifactRepository getDistributionManagementArtifactRepository() {
1027         return getArtifact().isSnapshot() && (getSnapshotArtifactRepository() != null)
1028                 ? getSnapshotArtifactRepository()
1029                 : getReleaseArtifactRepository();
1030     }
1031 
1032     public List<Repository> getPluginRepositories() {
1033         return getModel().getPluginRepositories();
1034     }
1035 
1036     public List<RemoteRepository> getRemoteProjectRepositories() {
1037         if (remoteProjectRepositories == null) {
1038             remoteProjectRepositories = new ArrayList<>();
1039         }
1040         return remoteProjectRepositories;
1041     }
1042 
1043     public List<RemoteRepository> getRemotePluginRepositories() {
1044         if (remotePluginRepositories == null) {
1045             remotePluginRepositories = new ArrayList<>();
1046         }
1047         return remotePluginRepositories;
1048     }
1049 
1050     public void setActiveProfiles(List<Profile> activeProfiles) {
1051         this.activeProfiles = activeProfiles;
1052     }
1053 
1054     public List<Profile> getActiveProfiles() {
1055         return activeProfiles;
1056     }
1057 
1058     public void setInjectedProfileIds(String source, List<String> injectedProfileIds) {
1059         if (injectedProfileIds != null) {
1060             this.injectedProfileIds.put(source, new ArrayList<>(injectedProfileIds));
1061         } else {
1062             this.injectedProfileIds.remove(source);
1063         }
1064     }
1065 
1066     /**
1067      * Gets the identifiers of all profiles that contributed to this project's effective model. This includes active
1068      * profiles from the project's POM and all its parent POMs as well as from external sources like the
1069      * {@code settings.xml}. The profile identifiers are grouped by the identifier of their source, e.g.
1070      * {@code <groupId>:<artifactId>:<version>} for a POM profile or {@code external} for profiles from the
1071      * {@code settings.xml}.
1072      *
1073      * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
1074      *         {@code null}.
1075      */
1076     public Map<String, List<String>> getInjectedProfileIds() {
1077         return this.injectedProfileIds;
1078     }
1079 
1080     /**
1081      * Add or replace an artifact. This method is now deprecated. Use the @{MavenProjectHelper} to attach artifacts to a
1082      * project. In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven
1083      * 3.0.x. Historically, it logged and ignored a second addition of the same g/a/v/c/t. Now it replaces the file for
1084      * the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
1085      * coordinates.
1086      *
1087      * @param artifact the artifact to add or replace.
1088      * @deprecated Please use {@link MavenProjectHelper}
1089      * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
1090      */
1091     public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
1092         // if already there we remove it and add again
1093         int index = attachedArtifacts.indexOf(artifact);
1094         if (index >= 0) {
1095             LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
1096             attachedArtifacts.set(index, artifact);
1097         } else {
1098             attachedArtifacts.add(artifact);
1099         }
1100     }
1101 
1102     /**
1103      * Returns a read-only list of the attached artifacts to this project.
1104      *
1105      * @return the attached artifacts of this project
1106      */
1107     public List<Artifact> getAttachedArtifacts() {
1108         if (attachedArtifacts == null) {
1109             attachedArtifacts = new ArrayList<>();
1110         }
1111         return Collections.unmodifiableList(attachedArtifacts);
1112     }
1113 
1114     public Xpp3Dom getGoalConfiguration(
1115             String pluginGroupId, String pluginArtifactId, String executionId, String goalId) {
1116         Xpp3Dom dom = null;
1117 
1118         if (getBuildPlugins() != null) {
1119             for (Plugin plugin : getBuildPlugins()) {
1120                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1121                     dom = (Xpp3Dom) plugin.getConfiguration();
1122 
1123                     if (executionId != null) {
1124                         for (PluginExecution execution : plugin.getExecutions()) {
1125                             if (executionId.equals(execution.getId())) {
1126                                 // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
1127                                 dom = (Xpp3Dom) execution.getConfiguration();
1128                                 break;
1129                             }
1130                         }
1131                     }
1132                     break;
1133                 }
1134             }
1135         }
1136 
1137         if (dom != null) {
1138             // make a copy so the original in the POM doesn't get messed with
1139             dom = new Xpp3Dom(dom);
1140         }
1141 
1142         return dom;
1143     }
1144 
1145     public MavenProject getExecutionProject() {
1146         return (executionProject == null ? this : executionProject);
1147     }
1148 
1149     public void setExecutionProject(MavenProject executionProject) {
1150         this.executionProject = executionProject;
1151     }
1152 
1153     public List<MavenProject> getCollectedProjects() {
1154         return collectedProjects;
1155     }
1156 
1157     public void setCollectedProjects(List<MavenProject> collectedProjects) {
1158         this.collectedProjects = collectedProjects;
1159     }
1160 
1161     /**
1162      * Direct dependencies that this project has.
1163      *
1164      * @return {@link Set} &lt; {@link Artifact} &gt;
1165      * @see #getArtifacts() to get all transitive dependencies
1166      */
1167     @Deprecated
1168     public Set<Artifact> getDependencyArtifacts() {
1169         return dependencyArtifacts;
1170     }
1171 
1172     @Deprecated
1173     public void setDependencyArtifacts(Set<Artifact> dependencyArtifacts) {
1174         this.dependencyArtifacts = dependencyArtifacts;
1175     }
1176 
1177     @Deprecated
1178     public void setReleaseArtifactRepository(ArtifactRepository releaseArtifactRepository) {
1179         this.releaseArtifactRepository = releaseArtifactRepository;
1180     }
1181 
1182     @Deprecated
1183     public void setSnapshotArtifactRepository(ArtifactRepository snapshotArtifactRepository) {
1184         this.snapshotArtifactRepository = snapshotArtifactRepository;
1185     }
1186 
1187     public void setOriginalModel(Model originalModel) {
1188         this.originalModel = originalModel;
1189     }
1190 
1191     public Model getOriginalModel() {
1192         return originalModel;
1193     }
1194 
1195     public void setManagedVersionMap(Map<String, Artifact> map) {
1196         managedVersionMap = map;
1197     }
1198 
1199     public Map<String, Artifact> getManagedVersionMap() {
1200         return managedVersionMap;
1201     }
1202 
1203     @Override
1204     public boolean equals(Object other) {
1205         if (other == this) {
1206             return true;
1207         } else {
1208             if (other instanceof MavenProject that) {
1209                 return Objects.equals(getArtifactId(), that.getArtifactId())
1210                         && Objects.equals(getGroupId(), that.getGroupId())
1211                         && Objects.equals(getVersion(), that.getVersion());
1212             } else {
1213                 return false;
1214             }
1215         }
1216     }
1217 
1218     @Override
1219     public int hashCode() {
1220         // Inlined hash avoids Object[] varargs allocation from Objects.hash()
1221         int result = 31 + Objects.hashCode(getGroupId());
1222         result = 31 * result + Objects.hashCode(getArtifactId());
1223         result = 31 * result + Objects.hashCode(getVersion());
1224         return result;
1225     }
1226 
1227     public List<Extension> getBuildExtensions() {
1228         Build build = getBuild();
1229         if ((build == null) || (build.getExtensions() == null)) {
1230             return Collections.emptyList();
1231         } else {
1232             return Collections.unmodifiableList(build.getExtensions());
1233         }
1234     }
1235 
1236     public void addProjectReference(MavenProject project) {
1237         projectReferences.put(
1238                 getProjectReferenceId(project.getGroupId(), project.getArtifactId(), project.getVersion()), project);
1239     }
1240 
1241     public Properties getProperties() {
1242         return getModel().getProperties();
1243     }
1244 
1245     public List<String> getFilters() {
1246         return getBuild().getFilters();
1247     }
1248 
1249     public Map<String, MavenProject> getProjectReferences() {
1250         return projectReferences;
1251     }
1252 
1253     public boolean isExecutionRoot() {
1254         return executionRoot;
1255     }
1256 
1257     public void setExecutionRoot(boolean executionRoot) {
1258         this.executionRoot = executionRoot;
1259     }
1260 
1261     public String getDefaultGoal() {
1262         return getBuild() != null ? getBuild().getDefaultGoal() : null;
1263     }
1264 
1265     public Plugin getPlugin(String pluginKey) {
1266         org.apache.maven.api.model.Plugin plugin =
1267                 getBuild().getDelegate().getPluginsAsMap().get(pluginKey);
1268         return plugin != null ? new Plugin(plugin, getBuild()) : null;
1269     }
1270 
1271     /**
1272      * Default toString
1273      */
1274     @Override
1275     public String toString() {
1276         StringBuilder sb = new StringBuilder(128);
1277         sb.append("MavenProject: ");
1278         sb.append(getGroupId());
1279         sb.append(':');
1280         sb.append(getArtifactId());
1281         sb.append(':');
1282         sb.append(getVersion());
1283         if (getFile() != null) {
1284             sb.append(" @ ");
1285             sb.append(getFile().getPath());
1286         }
1287 
1288         return sb.toString();
1289     }
1290 
1291     /**
1292      * @since 2.0.9
1293      */
1294     @Override
1295     public MavenProject clone() {
1296         MavenProject clone;
1297         try {
1298             clone = (MavenProject) super.clone();
1299         } catch (CloneNotSupportedException e) {
1300             throw new UnsupportedOperationException(e);
1301         }
1302 
1303         clone.deepCopy(this);
1304 
1305         return clone;
1306     }
1307 
1308     public void setModel(Model model) {
1309         this.model = model;
1310     }
1311 
1312     protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
1313         this.attachedArtifacts = attachedArtifacts;
1314     }
1315 
1316     /**
1317      * @deprecated Used only for the implementation of deprecated methods.
1318      */
1319     @Deprecated
1320     private void setSourceRootDirs(ProjectScope scope, Language language, List<String> roots) {
1321         sources.removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
1322         Path directory = getBaseDirectory();
1323         for (String root : roots) {
1324             addSourceRoot(new DefaultSourceRoot(scope, language, directory.resolve(root)));
1325         }
1326     }
1327 
1328     /**
1329      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1330      */
1331     @Deprecated(since = "4.0.0")
1332     protected void setCompileSourceRoots(List<String> compileSourceRoots) {
1333         setSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY, compileSourceRoots);
1334     }
1335 
1336     /**
1337      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1338      */
1339     @Deprecated(since = "4.0.0")
1340     protected void setTestCompileSourceRoots(List<String> testCompileSourceRoots) {
1341         setSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY, testCompileSourceRoots);
1342     }
1343 
1344     protected ArtifactRepository getReleaseArtifactRepository() {
1345         return releaseArtifactRepository;
1346     }
1347 
1348     protected ArtifactRepository getSnapshotArtifactRepository() {
1349         return snapshotArtifactRepository;
1350     }
1351 
1352     private void deepCopy(MavenProject project) {
1353         // disown the parent
1354 
1355         // copy fields
1356         file = project.file;
1357         basedir = project.basedir;
1358 
1359         // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
1360         // sure!
1361         if (project.getDependencyArtifacts() != null) {
1362             setDependencyArtifacts(Collections.unmodifiableSet(project.getDependencyArtifacts()));
1363         }
1364 
1365         if (project.getArtifacts() != null) {
1366             setArtifacts(Collections.unmodifiableSet(project.getArtifacts()));
1367         }
1368 
1369         if (project.getParentFile() != null) {
1370             parentFile = new File(project.getParentFile().getAbsolutePath());
1371         }
1372 
1373         if (project.getPluginArtifacts() != null) {
1374             setPluginArtifacts(Collections.unmodifiableSet(project.getPluginArtifacts()));
1375         }
1376 
1377         if (project.getReportArtifacts() != null) {
1378             setReportArtifacts(Collections.unmodifiableSet(project.getReportArtifacts()));
1379         }
1380 
1381         if (project.getExtensionArtifacts() != null) {
1382             setExtensionArtifacts(Collections.unmodifiableSet(project.getExtensionArtifacts()));
1383         }
1384 
1385         setParentArtifact((project.getParentArtifact()));
1386 
1387         if (project.getRemoteArtifactRepositories() != null) {
1388             setRemoteArtifactRepositories(Collections.unmodifiableList(project.getRemoteArtifactRepositories()));
1389         }
1390 
1391         if (project.getPluginArtifactRepositories() != null) {
1392             setPluginArtifactRepositories(Collections.unmodifiableList(project.getPluginArtifactRepositories()));
1393         }
1394 
1395         if (project.getActiveProfiles() != null) {
1396             setActiveProfiles((Collections.unmodifiableList(project.getActiveProfiles())));
1397         }
1398 
1399         if (project.getAttachedArtifacts() != null) {
1400             // clone properties modifiable by plugins in a forked lifecycle
1401             setAttachedArtifacts(new ArrayList<>(project.getAttachedArtifacts()));
1402         }
1403 
1404         // This property is not handled like others as we don't use public API.
1405         // The whole implementation of this `deepCopy` method may need revision,
1406         // but it would be the topic for a separated commit.
1407         sources = new LinkedHashSet<>(project.sources);
1408 
1409         if (project.getModel() != null) {
1410             setModel(project.getModel().clone());
1411         }
1412 
1413         if (project.getOriginalModel() != null) {
1414             setOriginalModel(project.getOriginalModel());
1415         }
1416 
1417         setExecutionRoot(project.isExecutionRoot());
1418 
1419         if (project.getArtifact() != null) {
1420             setArtifact(ArtifactUtils.copyArtifact(project.getArtifact()));
1421         }
1422 
1423         if (project.getManagedVersionMap() != null) {
1424             setManagedVersionMap(project.getManagedVersionMap());
1425         }
1426 
1427         lifecyclePhases.addAll(project.lifecyclePhases);
1428     }
1429 
1430     private static String getProjectReferenceId(String groupId, String artifactId, String version) {
1431         StringBuilder buffer = new StringBuilder(128);
1432         buffer.append(groupId).append(':').append(artifactId).append(':').append(version);
1433         return buffer.toString();
1434     }
1435 
1436     /**
1437      * Sets the value of the context value of this project identified by the given key. If the supplied value is
1438      * <code>null</code>, the context value is removed from this project. Context values are intended to allow core
1439      * extensions to associate derived state with project instances.
1440      */
1441     public void setContextValue(String key, Object value) {
1442         if (context == null) {
1443             context = new HashMap<>();
1444         }
1445         if (value != null) {
1446             context.put(key, value);
1447         } else {
1448             context.remove(key);
1449         }
1450     }
1451 
1452     /**
1453      * Returns context value of this project associated with the given key or null if this project has no such value.
1454      */
1455     public Object getContextValue(String key) {
1456         if (context == null) {
1457             return null;
1458         }
1459         return context.get(key);
1460     }
1461 
1462     /**
1463      * Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
1464      * for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
1465      * without prior notice and must not be used by plugins.
1466      *
1467      * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
1468      */
1469     public void setClassRealm(ClassRealm classRealm) {
1470         this.classRealm = classRealm;
1471     }
1472 
1473     /**
1474      * Gets the project's class realm. This class realm hosts the build extensions of the project.
1475      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1476      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1477      * used by plugins.
1478      *
1479      * @return The project's class realm or {@code null}.
1480      */
1481     public ClassRealm getClassRealm() {
1482         return classRealm;
1483     }
1484 
1485     /**
1486      * Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
1487      * This is an internal utility method that is only public for technical reasons, it is not part of the public API.
1488      * In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
1489      *
1490      * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
1491      */
1492     public void setExtensionDependencyFilter(DependencyFilter extensionDependencyFilter) {
1493         this.extensionDependencyFilter = extensionDependencyFilter;
1494     }
1495 
1496     /**
1497      * Gets the dependency filter used to exclude shared extension artifacts from plugin realms.
1498      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1499      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1500      * used by plugins.
1501      *
1502      * @return The dependency filter or {@code null}.
1503      */
1504     public DependencyFilter getExtensionDependencyFilter() {
1505         return extensionDependencyFilter;
1506     }
1507 
1508     /**
1509      * Sets the transitive dependency artifacts that have been resolved/collected for this project.
1510      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1511      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1512      * used by plugins.
1513      *
1514      * @param artifacts The set of artifacts, may be {@code null}.
1515      */
1516     public void setResolvedArtifacts(Set<Artifact> artifacts) {
1517         this.resolvedArtifacts = (artifacts != null) ? artifacts : Collections.emptySet();
1518         this.artifacts = null;
1519         this.artifactMap = null;
1520     }
1521 
1522     /**
1523      * Sets the scope filter to select the artifacts being exposed to the currently executed mojo.
1524      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1525      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1526      * used by plugins.
1527      *
1528      * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
1529      */
1530     public void setArtifactFilter(ArtifactFilter artifactFilter) {
1531         this.artifactFilter = artifactFilter;
1532         this.artifacts = null;
1533         this.artifactMap = null;
1534     }
1535 
1536     /**
1537      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1538      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1539      * used by plugins.
1540      *
1541      * @param phase The phase to check for, must not be {@code null}.
1542      * @return {@code true} if the phase has been seen.
1543      */
1544     public boolean hasLifecyclePhase(String phase) {
1545         return lifecyclePhases.contains(phase);
1546     }
1547 
1548     /**
1549      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1550      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1551      * used by plugins.
1552      *
1553      * @param lifecyclePhase The lifecycle phase to add, must not be {@code null}.
1554      */
1555     public void addLifecyclePhase(String lifecyclePhase) {
1556         lifecyclePhases.add(lifecyclePhase);
1557     }
1558 
1559     // ----------------------------------------------------------------------------------------------------------------
1560     //
1561     //
1562     // D E P R E C A T E D
1563     //
1564     //
1565     // ----------------------------------------------------------------------------------------------------------------
1566     //
1567     // Everything below will be removed for Maven 4.0.0
1568     //
1569     // ----------------------------------------------------------------------------------------------------------------
1570 
1571     private ProjectBuildingRequest projectBuilderConfiguration;
1572 
1573     private Map<String, String> moduleAdjustments;
1574 
1575     @Deprecated // This appears only to be used in test code
1576     public String getModulePathAdjustment(MavenProject moduleProject) throws IOException {
1577         // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
1578         // is coming from the repository??
1579         String module = moduleProject.getArtifactId();
1580 
1581         File moduleFile = moduleProject.getFile();
1582 
1583         if (moduleFile != null) {
1584             File moduleDir = moduleFile.getCanonicalFile().getParentFile();
1585 
1586             module = moduleDir.getName();
1587         }
1588 
1589         if (moduleAdjustments == null) {
1590             moduleAdjustments = new HashMap<>();
1591 
1592             List<String> modules = getModules();
1593             if (modules != null) {
1594                 for (String modulePath : modules) {
1595                     String moduleName = modulePath;
1596 
1597                     if (moduleName.endsWith("/") || moduleName.endsWith("\\")) {
1598                         moduleName = moduleName.substring(0, moduleName.length() - 1);
1599                     }
1600 
1601                     int lastSlash = moduleName.lastIndexOf('/');
1602 
1603                     if (lastSlash < 0) {
1604                         lastSlash = moduleName.lastIndexOf('\\');
1605                     }
1606 
1607                     String adjustment = null;
1608 
1609                     if (lastSlash > -1) {
1610                         moduleName = moduleName.substring(lastSlash + 1);
1611                         adjustment = modulePath.substring(0, lastSlash);
1612                     }
1613 
1614                     moduleAdjustments.put(moduleName, adjustment);
1615                 }
1616             }
1617         }
1618 
1619         return moduleAdjustments.get(module);
1620     }
1621 
1622     @Deprecated
1623     public Set<Artifact> createArtifacts(ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter)
1624             throws InvalidDependencyVersionException {
1625         return DefaultProjectArtifactFactory.createArtifacts(
1626                 artifactFactory, getModel().getDependencies(), inheritedScope, filter, this);
1627     }
1628 
1629     @Deprecated
1630     protected void setScriptSourceRoots(List<String> scriptSourceRoots) {
1631         setSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT, scriptSourceRoots);
1632     }
1633 
1634     @Deprecated
1635     public void addScriptSourceRoot(String path) {
1636         addSourceRoot(ProjectScope.MAIN, Language.SCRIPT, path);
1637     }
1638 
1639     @Deprecated
1640     public List<String> getScriptSourceRoots() {
1641         return getSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT);
1642     }
1643 
1644     @Deprecated
1645     public List<Artifact> getCompileArtifacts() {
1646         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1647 
1648         for (Artifact a : getArtifacts()) {
1649             // TODO classpath check doesn't belong here - that's the other method
1650             if (a.getArtifactHandler().isAddedToClasspath()) {
1651                 // TODO let the scope handler deal with this
1652                 if (isCompilePathElement(a.getScope())) {
1653                     list.add(a);
1654                 }
1655             }
1656         }
1657         return list;
1658     }
1659 
1660     @Deprecated
1661     public List<Dependency> getCompileDependencies() {
1662         Set<Artifact> artifacts = getArtifacts();
1663 
1664         if ((artifacts == null) || artifacts.isEmpty()) {
1665             return Collections.emptyList();
1666         }
1667 
1668         List<Dependency> list = new ArrayList<>(artifacts.size());
1669 
1670         for (Artifact a : getArtifacts()) {
1671             // TODO let the scope handler deal with this
1672             if (isCompilePathElement(a.getScope())) {
1673                 Dependency dependency = new Dependency();
1674 
1675                 dependency.setArtifactId(a.getArtifactId());
1676                 dependency.setGroupId(a.getGroupId());
1677                 dependency.setVersion(a.getVersion());
1678                 dependency.setScope(a.getScope());
1679                 dependency.setType(a.getType());
1680                 dependency.setClassifier(a.getClassifier());
1681 
1682                 list.add(dependency);
1683             }
1684         }
1685         return Collections.unmodifiableList(list);
1686     }
1687 
1688     @Deprecated
1689     public List<Artifact> getTestArtifacts() {
1690         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1691 
1692         for (Artifact a : getArtifacts()) {
1693             // TODO classpath check doesn't belong here - that's the other method
1694             if (a.getArtifactHandler().isAddedToClasspath()) {
1695                 list.add(a);
1696             }
1697         }
1698         return list;
1699     }
1700 
1701     @Deprecated
1702     public List<Dependency> getTestDependencies() {
1703         Set<Artifact> artifacts = getArtifacts();
1704 
1705         if ((artifacts == null) || artifacts.isEmpty()) {
1706             return Collections.emptyList();
1707         }
1708 
1709         List<Dependency> list = new ArrayList<>(artifacts.size());
1710 
1711         for (Artifact a : getArtifacts()) {
1712             Dependency dependency = new Dependency();
1713 
1714             dependency.setArtifactId(a.getArtifactId());
1715             dependency.setGroupId(a.getGroupId());
1716             dependency.setVersion(a.getVersion());
1717             dependency.setScope(a.getScope());
1718             dependency.setType(a.getType());
1719             dependency.setClassifier(a.getClassifier());
1720 
1721             list.add(dependency);
1722         }
1723         return Collections.unmodifiableList(list);
1724     }
1725 
1726     @Deprecated // used by the Maven ITs
1727     public List<Dependency> getRuntimeDependencies() {
1728         Set<Artifact> artifacts = getArtifacts();
1729 
1730         if ((artifacts == null) || artifacts.isEmpty()) {
1731             return Collections.emptyList();
1732         }
1733 
1734         List<Dependency> list = new ArrayList<>(artifacts.size());
1735 
1736         for (Artifact a : getArtifacts()) {
1737             // TODO let the scope handler deal with this
1738             if (isRuntimePathElement(a.getScope())) {
1739                 Dependency dependency = new Dependency();
1740 
1741                 dependency.setArtifactId(a.getArtifactId());
1742                 dependency.setGroupId(a.getGroupId());
1743                 dependency.setVersion(a.getVersion());
1744                 dependency.setScope(a.getScope());
1745                 dependency.setType(a.getType());
1746                 dependency.setClassifier(a.getClassifier());
1747 
1748                 list.add(dependency);
1749             }
1750         }
1751         return Collections.unmodifiableList(list);
1752     }
1753 
1754     @Deprecated
1755     public List<Artifact> getRuntimeArtifacts() {
1756         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1757 
1758         for (Artifact a : getArtifacts()) {
1759             // TODO classpath check doesn't belong here - that's the other method
1760             if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) {
1761                 list.add(a);
1762             }
1763         }
1764         return list;
1765     }
1766 
1767     @Deprecated
1768     public List<String> getSystemClasspathElements() throws DependencyResolutionRequiredException {
1769         List<String> list = new ArrayList<>(getArtifacts().size());
1770 
1771         String d = getBuild().getOutputDirectory();
1772         if (d != null) {
1773             list.add(d);
1774         }
1775 
1776         for (Artifact a : getArtifacts()) {
1777             if (a.getArtifactHandler().isAddedToClasspath()) {
1778                 // TODO let the scope handler deal with this
1779                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1780                     File f = a.getFile();
1781                     if (f != null) {
1782                         list.add(f.getPath());
1783                     }
1784                 }
1785             }
1786         }
1787         return list;
1788     }
1789 
1790     @Deprecated
1791     public List<Artifact> getSystemArtifacts() {
1792         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1793 
1794         for (Artifact a : getArtifacts()) {
1795             // TODO classpath check doesn't belong here - that's the other method
1796             if (a.getArtifactHandler().isAddedToClasspath()) {
1797                 // TODO let the scope handler deal with this
1798                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1799                     list.add(a);
1800                 }
1801             }
1802         }
1803         return list;
1804     }
1805 
1806     @Deprecated
1807     public List<Dependency> getSystemDependencies() {
1808         Set<Artifact> artifacts = getArtifacts();
1809 
1810         if ((artifacts == null) || artifacts.isEmpty()) {
1811             return Collections.emptyList();
1812         }
1813 
1814         List<Dependency> list = new ArrayList<>(artifacts.size());
1815 
1816         for (Artifact a : getArtifacts()) {
1817             // TODO let the scope handler deal with this
1818             if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1819                 Dependency dependency = new Dependency();
1820 
1821                 dependency.setArtifactId(a.getArtifactId());
1822                 dependency.setGroupId(a.getGroupId());
1823                 dependency.setVersion(a.getVersion());
1824                 dependency.setScope(a.getScope());
1825                 dependency.setType(a.getType());
1826                 dependency.setClassifier(a.getClassifier());
1827 
1828                 list.add(dependency);
1829             }
1830         }
1831         return Collections.unmodifiableList(list);
1832     }
1833 
1834     @Deprecated
1835     public void setReporting(Reporting reporting) {
1836         getModel().setReporting(reporting);
1837     }
1838 
1839     @Deprecated
1840     public Reporting getReporting() {
1841         return getModel().getReporting();
1842     }
1843 
1844     @Deprecated
1845     public void setReportArtifacts(Set<Artifact> reportArtifacts) {
1846         this.reportArtifacts = reportArtifacts;
1847 
1848         reportArtifactMap = null;
1849     }
1850 
1851     @Deprecated
1852     public Set<Artifact> getReportArtifacts() {
1853         return reportArtifacts;
1854     }
1855 
1856     @Deprecated
1857     public Map<String, Artifact> getReportArtifactMap() {
1858         if (reportArtifactMap == null) {
1859             reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getReportArtifacts());
1860         }
1861 
1862         return reportArtifactMap;
1863     }
1864 
1865     @Deprecated
1866     public void setExtensionArtifacts(Set<Artifact> extensionArtifacts) {
1867         this.extensionArtifacts = extensionArtifacts;
1868         extensionArtifactMap = null;
1869     }
1870 
1871     @Deprecated
1872     public Set<Artifact> getExtensionArtifacts() {
1873         return extensionArtifacts;
1874     }
1875 
1876     @Deprecated
1877     public Map<String, Artifact> getExtensionArtifactMap() {
1878         if (extensionArtifactMap == null) {
1879             extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getExtensionArtifacts());
1880         }
1881 
1882         return extensionArtifactMap;
1883     }
1884 
1885     @Deprecated
1886     public List<ReportPlugin> getReportPlugins() {
1887         if (getModel().getReporting() == null) {
1888             return Collections.emptyList();
1889         }
1890         return Collections.unmodifiableList(getModel().getReporting().getPlugins());
1891     }
1892 
1893     @Deprecated
1894     public Xpp3Dom getReportConfiguration(String pluginGroupId, String pluginArtifactId, String reportSetId) {
1895         Xpp3Dom dom = null;
1896 
1897         // ----------------------------------------------------------------------
1898         // I would like to be able to look up the Mojo object using a key but
1899         // we have a limitation in modello that will be remedied shortly. So
1900         // for now I have to iterate through and see what we have.
1901         // ----------------------------------------------------------------------
1902 
1903         if (getReportPlugins() != null) {
1904             for (ReportPlugin plugin : getReportPlugins()) {
1905                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1906                     dom = (Xpp3Dom) plugin.getConfiguration();
1907 
1908                     if (reportSetId != null) {
1909                         ReportSet reportSet = plugin.getReportSetsAsMap().get(reportSetId);
1910                         if (reportSet != null) {
1911                             Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
1912                             if (executionConfiguration != null) {
1913                                 Xpp3Dom newDom = new Xpp3Dom(executionConfiguration);
1914                                 dom = Xpp3Dom.mergeXpp3Dom(newDom, dom);
1915                             }
1916                         }
1917                     }
1918                     break;
1919                 }
1920             }
1921         }
1922 
1923         if (dom != null) {
1924             // make a copy so the original in the POM doesn't get messed with
1925             dom = new Xpp3Dom(dom);
1926         }
1927 
1928         return dom;
1929     }
1930 
1931     /**
1932      * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
1933      */
1934     @Deprecated
1935     public void attachArtifact(String type, String classifier, File file) {}
1936 
1937     /**
1938      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1939      */
1940     @Deprecated
1941     public void writeModel(Writer writer) throws IOException {
1942         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1943         pomWriter.write(writer, getModel());
1944     }
1945 
1946     /**
1947      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1948      */
1949     @Deprecated
1950     public void writeOriginalModel(Writer writer) throws IOException {
1951         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1952         pomWriter.write(writer, getOriginalModel());
1953     }
1954 
1955     @Deprecated
1956     public Artifact replaceWithActiveArtifact(Artifact pluginArtifact) {
1957         return pluginArtifact;
1958     }
1959 
1960     /**
1961      * Gets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1962      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1963      *
1964      * @return The project building request or {@code null}.
1965      * @since 2.1
1966      */
1967     @Deprecated
1968     public ProjectBuildingRequest getProjectBuildingRequest() {
1969         return projectBuilderConfiguration;
1970     }
1971 
1972     /**
1973      * Sets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1974      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1975      *
1976      * @param projectBuildingRequest The project building request, may be {@code null}.
1977      * @since 2.1
1978      */
1979     // used by maven-dependency-tree
1980     @Deprecated
1981     public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
1982         this.projectBuilderConfiguration = projectBuildingRequest;
1983     }
1984 
1985     /**
1986      * @since 4.0.0
1987      * @return the rootDirectory for this project
1988      * @throws IllegalStateException if the rootDirectory cannot be found
1989      */
1990     public Path getRootDirectory() {
1991         if (rootDirectory == null) {
1992             throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
1993         }
1994         return rootDirectory;
1995     }
1996 
1997     public void setRootDirectory(Path rootDirectory) {
1998         this.rootDirectory = rootDirectory;
1999     }
2000 }