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     private 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         // TODO this should not be allowed to be null.
636         if (getModel().getName() != null) {
637             return getModel().getName();
638         } else {
639             return getArtifactId();
640         }
641     }
642 
643     public void setVersion(String version) {
644         getModel().setVersion(version);
645     }
646 
647     public String getVersion() {
648         String version = getModel().getVersion();
649 
650         if ((version == null) && (getModel().getParent() != null)) {
651             version = getModel().getParent().getVersion();
652         }
653 
654         return version;
655     }
656 
657     public String getPackaging() {
658         return getModel().getPackaging();
659     }
660 
661     public void setPackaging(String packaging) {
662         getModel().setPackaging(packaging);
663     }
664 
665     public void setInceptionYear(String inceptionYear) {
666         getModel().setInceptionYear(inceptionYear);
667     }
668 
669     public String getInceptionYear() {
670         return getModel().getInceptionYear();
671     }
672 
673     public void setUrl(String url) {
674         getModel().setUrl(url);
675     }
676 
677     public String getUrl() {
678         return getModel().getUrl();
679     }
680 
681     public Prerequisites getPrerequisites() {
682         return getModel().getPrerequisites();
683     }
684 
685     public void setIssueManagement(IssueManagement issueManagement) {
686         getModel().setIssueManagement(issueManagement);
687     }
688 
689     public CiManagement getCiManagement() {
690         return getModel().getCiManagement();
691     }
692 
693     public void setCiManagement(CiManagement ciManagement) {
694         getModel().setCiManagement(ciManagement);
695     }
696 
697     public IssueManagement getIssueManagement() {
698         return getModel().getIssueManagement();
699     }
700 
701     public void setDistributionManagement(DistributionManagement distributionManagement) {
702         getModel().setDistributionManagement(distributionManagement);
703     }
704 
705     public DistributionManagement getDistributionManagement() {
706         return getModel().getDistributionManagement();
707     }
708 
709     public void setDescription(String description) {
710         getModel().setDescription(description);
711     }
712 
713     public String getDescription() {
714         return getModel().getDescription();
715     }
716 
717     public void setOrganization(Organization organization) {
718         getModel().setOrganization(organization);
719     }
720 
721     public Organization getOrganization() {
722         return getModel().getOrganization();
723     }
724 
725     public void setScm(Scm scm) {
726         getModel().setScm(scm);
727     }
728 
729     public Scm getScm() {
730         return getModel().getScm();
731     }
732 
733     public void setMailingLists(List<MailingList> mailingLists) {
734         getModel().setMailingLists(mailingLists);
735     }
736 
737     public List<MailingList> getMailingLists() {
738         return getModel().getMailingLists();
739     }
740 
741     public void addMailingList(MailingList mailingList) {
742         getModel().addMailingList(mailingList);
743     }
744 
745     public void setDevelopers(List<Developer> developers) {
746         getModel().setDevelopers(developers);
747     }
748 
749     public List<Developer> getDevelopers() {
750         return getModel().getDevelopers();
751     }
752 
753     public void addDeveloper(Developer developer) {
754         getModel().addDeveloper(developer);
755     }
756 
757     public void setContributors(List<Contributor> contributors) {
758         getModel().setContributors(contributors);
759     }
760 
761     public List<Contributor> getContributors() {
762         return getModel().getContributors();
763     }
764 
765     public void addContributor(Contributor contributor) {
766         getModel().addContributor(contributor);
767     }
768 
769     public void setBuild(Build build) {
770         getModel().setBuild(build);
771     }
772 
773     public Build getBuild() {
774         return getModelBuild();
775     }
776 
777     /**
778      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)}.
779      */
780     @Deprecated(since = "4.0.0")
781     public List<Resource> getResources() {
782         return getResources(ProjectScope.MAIN);
783     }
784 
785     /**
786      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)}.
787      */
788     @Deprecated(since = "4.0.0")
789     public List<Resource> getTestResources() {
790         return getResources(ProjectScope.TEST);
791     }
792 
793     private List<Resource> getResources(final ProjectScope scope) {
794         return new AbstractSequentialList<>() {
795             private Stream<SourceRoot> sources() {
796                 return getEnabledSourceRoots(scope, Language.RESOURCES);
797             }
798 
799             @Override
800             public ListIterator<Resource> listIterator(int index) {
801                 return sources().map(MavenProject::toResource).toList().listIterator(index);
802             }
803 
804             @Override
805             public int size() {
806                 return Math.toIntExact(sources().count());
807             }
808 
809             @Override
810             public boolean isEmpty() {
811                 return sources().findAny().isEmpty();
812             }
813 
814             @Override
815             public boolean add(Resource resource) {
816                 addResource(scope, resource);
817                 return true;
818             }
819         };
820     }
821 
822     private static Resource toResource(SourceRoot sourceRoot) {
823         return new Resource(org.apache.maven.api.model.Resource.newBuilder()
824                 .directory(sourceRoot.directory().toString())
825                 .includes(sourceRoot.includes())
826                 .excludes(sourceRoot.excludes())
827                 .filtering(Boolean.toString(sourceRoot.stringFiltering()))
828                 .build());
829     }
830 
831     private void addResource(ProjectScope scope, Resource resource) {
832         addSourceRoot(new DefaultSourceRoot(getBaseDirectory(), scope, resource.getDelegate()));
833     }
834 
835     /**
836      * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
837      */
838     @Deprecated(since = "4.0.0")
839     public void addResource(Resource resource) {
840         addResource(ProjectScope.MAIN, resource);
841     }
842 
843     /**
844      * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
845      */
846     @Deprecated(since = "4.0.0")
847     public void addTestResource(Resource testResource) {
848         addResource(ProjectScope.TEST, testResource);
849     }
850 
851     public void setLicenses(List<License> licenses) {
852         getModel().setLicenses(licenses);
853     }
854 
855     public List<License> getLicenses() {
856         return getModel().getLicenses();
857     }
858 
859     public void addLicense(License license) {
860         getModel().addLicense(license);
861     }
862 
863     public void setArtifacts(Set<Artifact> artifacts) {
864         this.artifacts = artifacts;
865 
866         // flush the calculated artifactMap
867         artifactMap = null;
868     }
869 
870     /**
871      * All dependencies that this project has, including transitive ones. Contents are lazily populated, so depending on
872      * what phases have run dependencies in some scopes won't be included. e.g. if only compile phase has run,
873      * dependencies with scope test won't be included.
874      *
875      * @return {@link Set} &lt; {@link Artifact} &gt;
876      * @see #getDependencyArtifacts() to get only direct dependencies
877      */
878     public Set<Artifact> getArtifacts() {
879         if (artifacts == null) {
880             if (artifactFilter == null || resolvedArtifacts == null) {
881                 artifacts = new LinkedHashSet<>();
882             } else {
883                 artifacts = new LinkedHashSet<>(resolvedArtifacts.size() * 2);
884                 for (Artifact artifact : resolvedArtifacts) {
885                     if (artifactFilter.include(artifact)) {
886                         artifacts.add(artifact);
887                     }
888                 }
889             }
890         }
891         return artifacts;
892     }
893 
894     public Map<String, Artifact> getArtifactMap() {
895         if (artifactMap == null) {
896             artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
897         }
898         return artifactMap;
899     }
900 
901     public void setPluginArtifacts(Set<Artifact> pluginArtifacts) {
902         this.pluginArtifacts = pluginArtifacts;
903 
904         this.pluginArtifactMap = null;
905     }
906 
907     public Set<Artifact> getPluginArtifacts() {
908         return pluginArtifacts;
909     }
910 
911     public Map<String, Artifact> getPluginArtifactMap() {
912         if (pluginArtifactMap == null) {
913             pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getPluginArtifacts());
914         }
915 
916         return pluginArtifactMap;
917     }
918 
919     public void setParentArtifact(Artifact parentArtifact) {
920         this.parentArtifact = parentArtifact;
921     }
922 
923     public Artifact getParentArtifact() {
924         return parentArtifact;
925     }
926 
927     public List<Repository> getRepositories() {
928         return getModel().getRepositories();
929     }
930 
931     // ----------------------------------------------------------------------
932     // Plugins
933     // ----------------------------------------------------------------------
934 
935     public List<Plugin> getBuildPlugins() {
936         if (getModel().getBuild() == null) {
937             return Collections.emptyList();
938         }
939         return Collections.unmodifiableList(getModel().getBuild().getPlugins());
940     }
941 
942     public List<String> getModules() {
943         if (!getModel().getDelegate().getSubprojects().isEmpty()) {
944             return getModel().getDelegate().getSubprojects();
945         }
946         return getModel().getModules();
947     }
948 
949     public PluginManagement getPluginManagement() {
950         PluginManagement pluginMgmt = null;
951 
952         Build build = getModel().getBuild();
953         if (build != null) {
954             pluginMgmt = build.getPluginManagement();
955         }
956 
957         return pluginMgmt;
958     }
959 
960     private Build getModelBuild() {
961         Build build = getModel().getBuild();
962 
963         if (build == null) {
964             build = new Build();
965 
966             getModel().setBuild(build);
967         }
968 
969         return build;
970     }
971 
972     @Deprecated
973     public void setRemoteArtifactRepositories(List<ArtifactRepository> remoteArtifactRepositories) {
974         this.remoteArtifactRepositories = remoteArtifactRepositories;
975         this.remoteProjectRepositories = RepositoryUtils.toRepos(getRemoteArtifactRepositories());
976     }
977 
978     @Deprecated
979     public List<ArtifactRepository> getRemoteArtifactRepositories() {
980         if (remoteArtifactRepositories == null) {
981             remoteArtifactRepositories = new ArrayList<>();
982         }
983 
984         return remoteArtifactRepositories;
985     }
986 
987     @Deprecated
988     public void setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
989         this.pluginArtifactRepositories = pluginArtifactRepositories;
990         this.remotePluginRepositories = RepositoryUtils.toRepos(getPluginArtifactRepositories());
991     }
992 
993     /**
994      * @return a list of ArtifactRepository objects constructed from the Repository objects returned by
995      *         getPluginRepositories.
996      */
997     @Deprecated
998     public List<ArtifactRepository> getPluginArtifactRepositories() {
999         if (pluginArtifactRepositories == null) {
1000             pluginArtifactRepositories = new ArrayList<>();
1001         }
1002 
1003         return pluginArtifactRepositories;
1004     }
1005 
1006     @Deprecated
1007     public ArtifactRepository getDistributionManagementArtifactRepository() {
1008         return getArtifact().isSnapshot() && (getSnapshotArtifactRepository() != null)
1009                 ? getSnapshotArtifactRepository()
1010                 : getReleaseArtifactRepository();
1011     }
1012 
1013     public List<Repository> getPluginRepositories() {
1014         return getModel().getPluginRepositories();
1015     }
1016 
1017     public List<RemoteRepository> getRemoteProjectRepositories() {
1018         if (remoteProjectRepositories == null) {
1019             remoteProjectRepositories = new ArrayList<>();
1020         }
1021         return remoteProjectRepositories;
1022     }
1023 
1024     public List<RemoteRepository> getRemotePluginRepositories() {
1025         if (remotePluginRepositories == null) {
1026             remotePluginRepositories = new ArrayList<>();
1027         }
1028         return remotePluginRepositories;
1029     }
1030 
1031     public void setActiveProfiles(List<Profile> activeProfiles) {
1032         this.activeProfiles = activeProfiles;
1033     }
1034 
1035     public List<Profile> getActiveProfiles() {
1036         return activeProfiles;
1037     }
1038 
1039     public void setInjectedProfileIds(String source, List<String> injectedProfileIds) {
1040         if (injectedProfileIds != null) {
1041             this.injectedProfileIds.put(source, new ArrayList<>(injectedProfileIds));
1042         } else {
1043             this.injectedProfileIds.remove(source);
1044         }
1045     }
1046 
1047     /**
1048      * Gets the identifiers of all profiles that contributed to this project's effective model. This includes active
1049      * profiles from the project's POM and all its parent POMs as well as from external sources like the
1050      * {@code settings.xml}. The profile identifiers are grouped by the identifier of their source, e.g.
1051      * {@code <groupId>:<artifactId>:<version>} for a POM profile or {@code external} for profiles from the
1052      * {@code settings.xml}.
1053      *
1054      * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
1055      *         {@code null}.
1056      */
1057     public Map<String, List<String>> getInjectedProfileIds() {
1058         return this.injectedProfileIds;
1059     }
1060 
1061     /**
1062      * Add or replace an artifact. This method is now deprecated. Use the @{MavenProjectHelper} to attach artifacts to a
1063      * project. In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven
1064      * 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
1065      * the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
1066      * coordinates.
1067      *
1068      * @param artifact the artifact to add or replace.
1069      * @deprecated Please use {@link MavenProjectHelper}
1070      * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
1071      */
1072     public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
1073         // if already there we remove it and add again
1074         int index = attachedArtifacts.indexOf(artifact);
1075         if (index >= 0) {
1076             LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
1077             attachedArtifacts.set(index, artifact);
1078         } else {
1079             attachedArtifacts.add(artifact);
1080         }
1081     }
1082 
1083     /**
1084      * Returns a read-only list of the attached artifacts to this project.
1085      *
1086      * @return the attached artifacts of this project
1087      */
1088     public List<Artifact> getAttachedArtifacts() {
1089         if (attachedArtifacts == null) {
1090             attachedArtifacts = new ArrayList<>();
1091         }
1092         return Collections.unmodifiableList(attachedArtifacts);
1093     }
1094 
1095     public Xpp3Dom getGoalConfiguration(
1096             String pluginGroupId, String pluginArtifactId, String executionId, String goalId) {
1097         Xpp3Dom dom = null;
1098 
1099         if (getBuildPlugins() != null) {
1100             for (Plugin plugin : getBuildPlugins()) {
1101                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1102                     dom = (Xpp3Dom) plugin.getConfiguration();
1103 
1104                     if (executionId != null) {
1105                         for (PluginExecution execution : plugin.getExecutions()) {
1106                             if (executionId.equals(execution.getId())) {
1107                                 // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
1108                                 dom = (Xpp3Dom) execution.getConfiguration();
1109                                 break;
1110                             }
1111                         }
1112                     }
1113                     break;
1114                 }
1115             }
1116         }
1117 
1118         if (dom != null) {
1119             // make a copy so the original in the POM doesn't get messed with
1120             dom = new Xpp3Dom(dom);
1121         }
1122 
1123         return dom;
1124     }
1125 
1126     public MavenProject getExecutionProject() {
1127         return (executionProject == null ? this : executionProject);
1128     }
1129 
1130     public void setExecutionProject(MavenProject executionProject) {
1131         this.executionProject = executionProject;
1132     }
1133 
1134     public List<MavenProject> getCollectedProjects() {
1135         return collectedProjects;
1136     }
1137 
1138     public void setCollectedProjects(List<MavenProject> collectedProjects) {
1139         this.collectedProjects = collectedProjects;
1140     }
1141 
1142     /**
1143      * Direct dependencies that this project has.
1144      *
1145      * @return {@link Set} &lt; {@link Artifact} &gt;
1146      * @see #getArtifacts() to get all transitive dependencies
1147      */
1148     @Deprecated
1149     public Set<Artifact> getDependencyArtifacts() {
1150         return dependencyArtifacts;
1151     }
1152 
1153     @Deprecated
1154     public void setDependencyArtifacts(Set<Artifact> dependencyArtifacts) {
1155         this.dependencyArtifacts = dependencyArtifacts;
1156     }
1157 
1158     @Deprecated
1159     public void setReleaseArtifactRepository(ArtifactRepository releaseArtifactRepository) {
1160         this.releaseArtifactRepository = releaseArtifactRepository;
1161     }
1162 
1163     @Deprecated
1164     public void setSnapshotArtifactRepository(ArtifactRepository snapshotArtifactRepository) {
1165         this.snapshotArtifactRepository = snapshotArtifactRepository;
1166     }
1167 
1168     public void setOriginalModel(Model originalModel) {
1169         this.originalModel = originalModel;
1170     }
1171 
1172     public Model getOriginalModel() {
1173         return originalModel;
1174     }
1175 
1176     public void setManagedVersionMap(Map<String, Artifact> map) {
1177         managedVersionMap = map;
1178     }
1179 
1180     public Map<String, Artifact> getManagedVersionMap() {
1181         return managedVersionMap;
1182     }
1183 
1184     @Override
1185     public boolean equals(Object other) {
1186         if (other == this) {
1187             return true;
1188         } else {
1189             if (other instanceof MavenProject that) {
1190                 return Objects.equals(getArtifactId(), that.getArtifactId())
1191                         && Objects.equals(getGroupId(), that.getGroupId())
1192                         && Objects.equals(getVersion(), that.getVersion());
1193             } else {
1194                 return false;
1195             }
1196         }
1197     }
1198 
1199     @Override
1200     public int hashCode() {
1201         return Objects.hash(getGroupId(), getArtifactId(), getVersion());
1202     }
1203 
1204     public List<Extension> getBuildExtensions() {
1205         Build build = getBuild();
1206         if ((build == null) || (build.getExtensions() == null)) {
1207             return Collections.emptyList();
1208         } else {
1209             return Collections.unmodifiableList(build.getExtensions());
1210         }
1211     }
1212 
1213     public void addProjectReference(MavenProject project) {
1214         projectReferences.put(
1215                 getProjectReferenceId(project.getGroupId(), project.getArtifactId(), project.getVersion()), project);
1216     }
1217 
1218     public Properties getProperties() {
1219         return getModel().getProperties();
1220     }
1221 
1222     public List<String> getFilters() {
1223         return getBuild().getFilters();
1224     }
1225 
1226     public Map<String, MavenProject> getProjectReferences() {
1227         return projectReferences;
1228     }
1229 
1230     public boolean isExecutionRoot() {
1231         return executionRoot;
1232     }
1233 
1234     public void setExecutionRoot(boolean executionRoot) {
1235         this.executionRoot = executionRoot;
1236     }
1237 
1238     public String getDefaultGoal() {
1239         return getBuild() != null ? getBuild().getDefaultGoal() : null;
1240     }
1241 
1242     public Plugin getPlugin(String pluginKey) {
1243         return getBuild().getPluginsAsMap().get(pluginKey);
1244     }
1245 
1246     /**
1247      * Default toString
1248      */
1249     @Override
1250     public String toString() {
1251         StringBuilder sb = new StringBuilder(128);
1252         sb.append("MavenProject: ");
1253         sb.append(getGroupId());
1254         sb.append(':');
1255         sb.append(getArtifactId());
1256         sb.append(':');
1257         sb.append(getVersion());
1258         if (getFile() != null) {
1259             sb.append(" @ ");
1260             sb.append(getFile().getPath());
1261         }
1262 
1263         return sb.toString();
1264     }
1265 
1266     /**
1267      * @since 2.0.9
1268      */
1269     @Override
1270     public MavenProject clone() {
1271         MavenProject clone;
1272         try {
1273             clone = (MavenProject) super.clone();
1274         } catch (CloneNotSupportedException e) {
1275             throw new UnsupportedOperationException(e);
1276         }
1277 
1278         clone.deepCopy(this);
1279 
1280         return clone;
1281     }
1282 
1283     public void setModel(Model model) {
1284         this.model = model;
1285     }
1286 
1287     protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
1288         this.attachedArtifacts = attachedArtifacts;
1289     }
1290 
1291     /**
1292      * @deprecated Used only for the implementation of deprecated methods.
1293      */
1294     @Deprecated
1295     private void setSourceRootDirs(ProjectScope scope, Language language, List<String> roots) {
1296         sources.removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
1297         Path directory = getBaseDirectory();
1298         for (String root : roots) {
1299             addSourceRoot(new DefaultSourceRoot(scope, language, directory.resolve(root)));
1300         }
1301     }
1302 
1303     /**
1304      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1305      */
1306     @Deprecated(since = "4.0.0")
1307     protected void setCompileSourceRoots(List<String> compileSourceRoots) {
1308         setSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY, compileSourceRoots);
1309     }
1310 
1311     /**
1312      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1313      */
1314     @Deprecated(since = "4.0.0")
1315     protected void setTestCompileSourceRoots(List<String> testCompileSourceRoots) {
1316         setSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY, testCompileSourceRoots);
1317     }
1318 
1319     protected ArtifactRepository getReleaseArtifactRepository() {
1320         return releaseArtifactRepository;
1321     }
1322 
1323     protected ArtifactRepository getSnapshotArtifactRepository() {
1324         return snapshotArtifactRepository;
1325     }
1326 
1327     private void deepCopy(MavenProject project) {
1328         // disown the parent
1329 
1330         // copy fields
1331         file = project.file;
1332         basedir = project.basedir;
1333 
1334         // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
1335         // sure!
1336         if (project.getDependencyArtifacts() != null) {
1337             setDependencyArtifacts(Collections.unmodifiableSet(project.getDependencyArtifacts()));
1338         }
1339 
1340         if (project.getArtifacts() != null) {
1341             setArtifacts(Collections.unmodifiableSet(project.getArtifacts()));
1342         }
1343 
1344         if (project.getParentFile() != null) {
1345             parentFile = new File(project.getParentFile().getAbsolutePath());
1346         }
1347 
1348         if (project.getPluginArtifacts() != null) {
1349             setPluginArtifacts(Collections.unmodifiableSet(project.getPluginArtifacts()));
1350         }
1351 
1352         if (project.getReportArtifacts() != null) {
1353             setReportArtifacts(Collections.unmodifiableSet(project.getReportArtifacts()));
1354         }
1355 
1356         if (project.getExtensionArtifacts() != null) {
1357             setExtensionArtifacts(Collections.unmodifiableSet(project.getExtensionArtifacts()));
1358         }
1359 
1360         setParentArtifact((project.getParentArtifact()));
1361 
1362         if (project.getRemoteArtifactRepositories() != null) {
1363             setRemoteArtifactRepositories(Collections.unmodifiableList(project.getRemoteArtifactRepositories()));
1364         }
1365 
1366         if (project.getPluginArtifactRepositories() != null) {
1367             setPluginArtifactRepositories(Collections.unmodifiableList(project.getPluginArtifactRepositories()));
1368         }
1369 
1370         if (project.getActiveProfiles() != null) {
1371             setActiveProfiles((Collections.unmodifiableList(project.getActiveProfiles())));
1372         }
1373 
1374         if (project.getAttachedArtifacts() != null) {
1375             // clone properties modifiable by plugins in a forked lifecycle
1376             setAttachedArtifacts(new ArrayList<>(project.getAttachedArtifacts()));
1377         }
1378 
1379         // This property is not handled like others as we don't use public API.
1380         // The whole implementation of this `deepCopy` method may need revision,
1381         // but it would be the topic for a separated commit.
1382         sources = new LinkedHashSet<>(project.sources);
1383 
1384         if (project.getModel() != null) {
1385             setModel(project.getModel().clone());
1386         }
1387 
1388         if (project.getOriginalModel() != null) {
1389             setOriginalModel(project.getOriginalModel());
1390         }
1391 
1392         setExecutionRoot(project.isExecutionRoot());
1393 
1394         if (project.getArtifact() != null) {
1395             setArtifact(ArtifactUtils.copyArtifact(project.getArtifact()));
1396         }
1397 
1398         if (project.getManagedVersionMap() != null) {
1399             setManagedVersionMap(project.getManagedVersionMap());
1400         }
1401 
1402         lifecyclePhases.addAll(project.lifecyclePhases);
1403     }
1404 
1405     private static String getProjectReferenceId(String groupId, String artifactId, String version) {
1406         StringBuilder buffer = new StringBuilder(128);
1407         buffer.append(groupId).append(':').append(artifactId).append(':').append(version);
1408         return buffer.toString();
1409     }
1410 
1411     /**
1412      * Sets the value of the context value of this project identified by the given key. If the supplied value is
1413      * <code>null</code>, the context value is removed from this project. Context values are intended to allow core
1414      * extensions to associate derived state with project instances.
1415      */
1416     public void setContextValue(String key, Object value) {
1417         if (context == null) {
1418             context = new HashMap<>();
1419         }
1420         if (value != null) {
1421             context.put(key, value);
1422         } else {
1423             context.remove(key);
1424         }
1425     }
1426 
1427     /**
1428      * Returns context value of this project associated with the given key or null if this project has no such value.
1429      */
1430     public Object getContextValue(String key) {
1431         if (context == null) {
1432             return null;
1433         }
1434         return context.get(key);
1435     }
1436 
1437     /**
1438      * Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
1439      * for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
1440      * without prior notice and must not be used by plugins.
1441      *
1442      * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
1443      */
1444     public void setClassRealm(ClassRealm classRealm) {
1445         this.classRealm = classRealm;
1446     }
1447 
1448     /**
1449      * Gets the project's class realm. This class realm hosts the build extensions of the project.
1450      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1451      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1452      * used by plugins.
1453      *
1454      * @return The project's class realm or {@code null}.
1455      */
1456     public ClassRealm getClassRealm() {
1457         return classRealm;
1458     }
1459 
1460     /**
1461      * Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
1462      * This is an internal utility method that is only public for technical reasons, it is not part of the public API.
1463      * In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
1464      *
1465      * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
1466      */
1467     public void setExtensionDependencyFilter(DependencyFilter extensionDependencyFilter) {
1468         this.extensionDependencyFilter = extensionDependencyFilter;
1469     }
1470 
1471     /**
1472      * Gets the dependency filter used to exclude shared extension artifacts from plugin realms.
1473      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1474      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1475      * used by plugins.
1476      *
1477      * @return The dependency filter or {@code null}.
1478      */
1479     public DependencyFilter getExtensionDependencyFilter() {
1480         return extensionDependencyFilter;
1481     }
1482 
1483     /**
1484      * Sets the transitive dependency artifacts that have been resolved/collected for this project.
1485      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1486      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1487      * used by plugins.
1488      *
1489      * @param artifacts The set of artifacts, may be {@code null}.
1490      */
1491     public void setResolvedArtifacts(Set<Artifact> artifacts) {
1492         this.resolvedArtifacts = (artifacts != null) ? artifacts : Collections.emptySet();
1493         this.artifacts = null;
1494         this.artifactMap = null;
1495     }
1496 
1497     /**
1498      * Sets the scope filter to select the artifacts being exposed to the currently executed mojo.
1499      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1500      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1501      * used by plugins.
1502      *
1503      * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
1504      */
1505     public void setArtifactFilter(ArtifactFilter artifactFilter) {
1506         this.artifactFilter = artifactFilter;
1507         this.artifacts = null;
1508         this.artifactMap = null;
1509     }
1510 
1511     /**
1512      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1513      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1514      * used by plugins.
1515      *
1516      * @param phase The phase to check for, must not be {@code null}.
1517      * @return {@code true} if the phase has been seen.
1518      */
1519     public boolean hasLifecyclePhase(String phase) {
1520         return lifecyclePhases.contains(phase);
1521     }
1522 
1523     /**
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 lifecyclePhase The lifecycle phase to add, must not be {@code null}.
1529      */
1530     public void addLifecyclePhase(String lifecyclePhase) {
1531         lifecyclePhases.add(lifecyclePhase);
1532     }
1533 
1534     // ----------------------------------------------------------------------------------------------------------------
1535     //
1536     //
1537     // D E P R E C A T E D
1538     //
1539     //
1540     // ----------------------------------------------------------------------------------------------------------------
1541     //
1542     // Everything below will be removed for Maven 4.0.0
1543     //
1544     // ----------------------------------------------------------------------------------------------------------------
1545 
1546     private ProjectBuildingRequest projectBuilderConfiguration;
1547 
1548     private Map<String, String> moduleAdjustments;
1549 
1550     @Deprecated // This appears only to be used in test code
1551     public String getModulePathAdjustment(MavenProject moduleProject) throws IOException {
1552         // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
1553         // is coming from the repository??
1554         String module = moduleProject.getArtifactId();
1555 
1556         File moduleFile = moduleProject.getFile();
1557 
1558         if (moduleFile != null) {
1559             File moduleDir = moduleFile.getCanonicalFile().getParentFile();
1560 
1561             module = moduleDir.getName();
1562         }
1563 
1564         if (moduleAdjustments == null) {
1565             moduleAdjustments = new HashMap<>();
1566 
1567             List<String> modules = getModules();
1568             if (modules != null) {
1569                 for (String modulePath : modules) {
1570                     String moduleName = modulePath;
1571 
1572                     if (moduleName.endsWith("/") || moduleName.endsWith("\\")) {
1573                         moduleName = moduleName.substring(0, moduleName.length() - 1);
1574                     }
1575 
1576                     int lastSlash = moduleName.lastIndexOf('/');
1577 
1578                     if (lastSlash < 0) {
1579                         lastSlash = moduleName.lastIndexOf('\\');
1580                     }
1581 
1582                     String adjustment = null;
1583 
1584                     if (lastSlash > -1) {
1585                         moduleName = moduleName.substring(lastSlash + 1);
1586                         adjustment = modulePath.substring(0, lastSlash);
1587                     }
1588 
1589                     moduleAdjustments.put(moduleName, adjustment);
1590                 }
1591             }
1592         }
1593 
1594         return moduleAdjustments.get(module);
1595     }
1596 
1597     @Deprecated
1598     public Set<Artifact> createArtifacts(ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter)
1599             throws InvalidDependencyVersionException {
1600         return DefaultProjectArtifactFactory.createArtifacts(
1601                 artifactFactory, getModel().getDependencies(), inheritedScope, filter, this);
1602     }
1603 
1604     @Deprecated
1605     protected void setScriptSourceRoots(List<String> scriptSourceRoots) {
1606         setSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT, scriptSourceRoots);
1607     }
1608 
1609     @Deprecated
1610     public void addScriptSourceRoot(String path) {
1611         addSourceRoot(ProjectScope.MAIN, Language.SCRIPT, path);
1612     }
1613 
1614     @Deprecated
1615     public List<String> getScriptSourceRoots() {
1616         return getSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT);
1617     }
1618 
1619     @Deprecated
1620     public List<Artifact> getCompileArtifacts() {
1621         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1622 
1623         for (Artifact a : getArtifacts()) {
1624             // TODO classpath check doesn't belong here - that's the other method
1625             if (a.getArtifactHandler().isAddedToClasspath()) {
1626                 // TODO let the scope handler deal with this
1627                 if (isCompilePathElement(a.getScope())) {
1628                     list.add(a);
1629                 }
1630             }
1631         }
1632         return list;
1633     }
1634 
1635     @Deprecated
1636     public List<Dependency> getCompileDependencies() {
1637         Set<Artifact> artifacts = getArtifacts();
1638 
1639         if ((artifacts == null) || artifacts.isEmpty()) {
1640             return Collections.emptyList();
1641         }
1642 
1643         List<Dependency> list = new ArrayList<>(artifacts.size());
1644 
1645         for (Artifact a : getArtifacts()) {
1646             // TODO let the scope handler deal with this
1647             if (isCompilePathElement(a.getScope())) {
1648                 Dependency dependency = new Dependency();
1649 
1650                 dependency.setArtifactId(a.getArtifactId());
1651                 dependency.setGroupId(a.getGroupId());
1652                 dependency.setVersion(a.getVersion());
1653                 dependency.setScope(a.getScope());
1654                 dependency.setType(a.getType());
1655                 dependency.setClassifier(a.getClassifier());
1656 
1657                 list.add(dependency);
1658             }
1659         }
1660         return Collections.unmodifiableList(list);
1661     }
1662 
1663     @Deprecated
1664     public List<Artifact> getTestArtifacts() {
1665         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1666 
1667         for (Artifact a : getArtifacts()) {
1668             // TODO classpath check doesn't belong here - that's the other method
1669             if (a.getArtifactHandler().isAddedToClasspath()) {
1670                 list.add(a);
1671             }
1672         }
1673         return list;
1674     }
1675 
1676     @Deprecated
1677     public List<Dependency> getTestDependencies() {
1678         Set<Artifact> artifacts = getArtifacts();
1679 
1680         if ((artifacts == null) || artifacts.isEmpty()) {
1681             return Collections.emptyList();
1682         }
1683 
1684         List<Dependency> list = new ArrayList<>(artifacts.size());
1685 
1686         for (Artifact a : getArtifacts()) {
1687             Dependency dependency = new Dependency();
1688 
1689             dependency.setArtifactId(a.getArtifactId());
1690             dependency.setGroupId(a.getGroupId());
1691             dependency.setVersion(a.getVersion());
1692             dependency.setScope(a.getScope());
1693             dependency.setType(a.getType());
1694             dependency.setClassifier(a.getClassifier());
1695 
1696             list.add(dependency);
1697         }
1698         return Collections.unmodifiableList(list);
1699     }
1700 
1701     @Deprecated // used by the Maven ITs
1702     public List<Dependency> getRuntimeDependencies() {
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             // TODO let the scope handler deal with this
1713             if (isRuntimePathElement(a.getScope())) {
1714                 Dependency dependency = new Dependency();
1715 
1716                 dependency.setArtifactId(a.getArtifactId());
1717                 dependency.setGroupId(a.getGroupId());
1718                 dependency.setVersion(a.getVersion());
1719                 dependency.setScope(a.getScope());
1720                 dependency.setType(a.getType());
1721                 dependency.setClassifier(a.getClassifier());
1722 
1723                 list.add(dependency);
1724             }
1725         }
1726         return Collections.unmodifiableList(list);
1727     }
1728 
1729     @Deprecated
1730     public List<Artifact> getRuntimeArtifacts() {
1731         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1732 
1733         for (Artifact a : getArtifacts()) {
1734             // TODO classpath check doesn't belong here - that's the other method
1735             if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) {
1736                 list.add(a);
1737             }
1738         }
1739         return list;
1740     }
1741 
1742     @Deprecated
1743     public List<String> getSystemClasspathElements() throws DependencyResolutionRequiredException {
1744         List<String> list = new ArrayList<>(getArtifacts().size());
1745 
1746         String d = getBuild().getOutputDirectory();
1747         if (d != null) {
1748             list.add(d);
1749         }
1750 
1751         for (Artifact a : getArtifacts()) {
1752             if (a.getArtifactHandler().isAddedToClasspath()) {
1753                 // TODO let the scope handler deal with this
1754                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1755                     File f = a.getFile();
1756                     if (f != null) {
1757                         list.add(f.getPath());
1758                     }
1759                 }
1760             }
1761         }
1762         return list;
1763     }
1764 
1765     @Deprecated
1766     public List<Artifact> getSystemArtifacts() {
1767         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1768 
1769         for (Artifact a : getArtifacts()) {
1770             // TODO classpath check doesn't belong here - that's the other method
1771             if (a.getArtifactHandler().isAddedToClasspath()) {
1772                 // TODO let the scope handler deal with this
1773                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1774                     list.add(a);
1775                 }
1776             }
1777         }
1778         return list;
1779     }
1780 
1781     @Deprecated
1782     public List<Dependency> getSystemDependencies() {
1783         Set<Artifact> artifacts = getArtifacts();
1784 
1785         if ((artifacts == null) || artifacts.isEmpty()) {
1786             return Collections.emptyList();
1787         }
1788 
1789         List<Dependency> list = new ArrayList<>(artifacts.size());
1790 
1791         for (Artifact a : getArtifacts()) {
1792             // TODO let the scope handler deal with this
1793             if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1794                 Dependency dependency = new Dependency();
1795 
1796                 dependency.setArtifactId(a.getArtifactId());
1797                 dependency.setGroupId(a.getGroupId());
1798                 dependency.setVersion(a.getVersion());
1799                 dependency.setScope(a.getScope());
1800                 dependency.setType(a.getType());
1801                 dependency.setClassifier(a.getClassifier());
1802 
1803                 list.add(dependency);
1804             }
1805         }
1806         return Collections.unmodifiableList(list);
1807     }
1808 
1809     @Deprecated
1810     public void setReporting(Reporting reporting) {
1811         getModel().setReporting(reporting);
1812     }
1813 
1814     @Deprecated
1815     public Reporting getReporting() {
1816         return getModel().getReporting();
1817     }
1818 
1819     @Deprecated
1820     public void setReportArtifacts(Set<Artifact> reportArtifacts) {
1821         this.reportArtifacts = reportArtifacts;
1822 
1823         reportArtifactMap = null;
1824     }
1825 
1826     @Deprecated
1827     public Set<Artifact> getReportArtifacts() {
1828         return reportArtifacts;
1829     }
1830 
1831     @Deprecated
1832     public Map<String, Artifact> getReportArtifactMap() {
1833         if (reportArtifactMap == null) {
1834             reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getReportArtifacts());
1835         }
1836 
1837         return reportArtifactMap;
1838     }
1839 
1840     @Deprecated
1841     public void setExtensionArtifacts(Set<Artifact> extensionArtifacts) {
1842         this.extensionArtifacts = extensionArtifacts;
1843         extensionArtifactMap = null;
1844     }
1845 
1846     @Deprecated
1847     public Set<Artifact> getExtensionArtifacts() {
1848         return extensionArtifacts;
1849     }
1850 
1851     @Deprecated
1852     public Map<String, Artifact> getExtensionArtifactMap() {
1853         if (extensionArtifactMap == null) {
1854             extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getExtensionArtifacts());
1855         }
1856 
1857         return extensionArtifactMap;
1858     }
1859 
1860     @Deprecated
1861     public List<ReportPlugin> getReportPlugins() {
1862         if (getModel().getReporting() == null) {
1863             return Collections.emptyList();
1864         }
1865         return Collections.unmodifiableList(getModel().getReporting().getPlugins());
1866     }
1867 
1868     @Deprecated
1869     public Xpp3Dom getReportConfiguration(String pluginGroupId, String pluginArtifactId, String reportSetId) {
1870         Xpp3Dom dom = null;
1871 
1872         // ----------------------------------------------------------------------
1873         // I would like to be able to look up the Mojo object using a key but
1874         // we have a limitation in modello that will be remedied shortly. So
1875         // for now I have to iterate through and see what we have.
1876         // ----------------------------------------------------------------------
1877 
1878         if (getReportPlugins() != null) {
1879             for (ReportPlugin plugin : getReportPlugins()) {
1880                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1881                     dom = (Xpp3Dom) plugin.getConfiguration();
1882 
1883                     if (reportSetId != null) {
1884                         ReportSet reportSet = plugin.getReportSetsAsMap().get(reportSetId);
1885                         if (reportSet != null) {
1886                             Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
1887                             if (executionConfiguration != null) {
1888                                 Xpp3Dom newDom = new Xpp3Dom(executionConfiguration);
1889                                 dom = Xpp3Dom.mergeXpp3Dom(newDom, dom);
1890                             }
1891                         }
1892                     }
1893                     break;
1894                 }
1895             }
1896         }
1897 
1898         if (dom != null) {
1899             // make a copy so the original in the POM doesn't get messed with
1900             dom = new Xpp3Dom(dom);
1901         }
1902 
1903         return dom;
1904     }
1905 
1906     /**
1907      * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
1908      */
1909     @Deprecated
1910     public void attachArtifact(String type, String classifier, File file) {}
1911 
1912     /**
1913      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1914      */
1915     @Deprecated
1916     public void writeModel(Writer writer) throws IOException {
1917         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1918         pomWriter.write(writer, getModel());
1919     }
1920 
1921     /**
1922      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1923      */
1924     @Deprecated
1925     public void writeOriginalModel(Writer writer) throws IOException {
1926         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1927         pomWriter.write(writer, getOriginalModel());
1928     }
1929 
1930     @Deprecated
1931     public Artifact replaceWithActiveArtifact(Artifact pluginArtifact) {
1932         return pluginArtifact;
1933     }
1934 
1935     /**
1936      * Gets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1937      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1938      *
1939      * @return The project building request or {@code null}.
1940      * @since 2.1
1941      */
1942     @Deprecated
1943     public ProjectBuildingRequest getProjectBuildingRequest() {
1944         return projectBuilderConfiguration;
1945     }
1946 
1947     /**
1948      * Sets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1949      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1950      *
1951      * @param projectBuildingRequest The project building request, may be {@code null}.
1952      * @since 2.1
1953      */
1954     // used by maven-dependency-tree
1955     @Deprecated
1956     public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
1957         this.projectBuilderConfiguration = projectBuildingRequest;
1958     }
1959 
1960     /**
1961      * @since 4.0.0
1962      * @return the rootDirectory for this project
1963      * @throws IllegalStateException if the rootDirectory cannot be found
1964      */
1965     public Path getRootDirectory() {
1966         if (rootDirectory == null) {
1967             throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
1968         }
1969         return rootDirectory;
1970     }
1971 
1972     public void setRootDirectory(Path rootDirectory) {
1973         this.rootDirectory = rootDirectory;
1974     }
1975 }