Allow to customize project models for actions.
diff --git a/java/maven/apichanges.xml b/java/maven/apichanges.xml
index 4616ee1..7335b70 100644
--- a/java/maven/apichanges.xml
+++ b/java/maven/apichanges.xml
@@ -83,6 +83,20 @@
     <!-- ACTUAL CHANGES BEGIN HERE: -->
 
     <changes>
+        <change id="evaluated-project">
+            <api name="general"/>
+            <summary>Project model can be customized for specific action or usage</summary>
+            <version major="2" minor="155"/>
+            <date day="10" month="8" year="2022"/>
+            <author login="sdedic"/>
+            <compatibility addition="yes" semantic="compatible"/>
+            <description>
+                Project state can be inspected with respect to an intended action to be run or used, and possible
+                customized properties or profiles. This allows clients to more precisely follow customizations in 
+                the project file and/or action mapping that would be applied when actually using project actions.
+            </description>
+            <class package="org.netbeans.modules.maven.api" name="NbMavenProject"/>
+        </change>
         <change id="plugin.conf.paths">
             <api name="general"/>
             <summary>Added helper method to get artifact paths from build plugin configurations.</summary>
diff --git a/java/maven/nbproject/project.properties b/java/maven/nbproject/project.properties
index d787680..b835cee 100644
--- a/java/maven/nbproject/project.properties
+++ b/java/maven/nbproject/project.properties
@@ -22,7 +22,7 @@
 javadoc.arch=${basedir}/arch.xml
 javahelp.hs=maven.hs
 extra.module.files=maven-nblib/
-spec.version.base: 2.154
+spec.version.base: 2.155
 
 # The CPExtender test fails in library processing (not randomly) since NetBeans 8.2; disabling.
 test.excludes=**/CPExtenderTest.class
diff --git a/java/maven/nbproject/project.xml b/java/maven/nbproject/project.xml
index e848bd1..df8df16 100644
--- a/java/maven/nbproject/project.xml
+++ b/java/maven/nbproject/project.xml
@@ -316,7 +316,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.80</specification-version>
+                        <specification-version>1.89</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
index 1d303f0..fe895eb 100644
--- a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
+++ b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
@@ -43,6 +43,7 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -69,12 +70,14 @@
 import org.netbeans.api.annotations.common.NullUnknown;
 import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
 import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectActionContext;
 import org.netbeans.api.queries.VisibilityQuery;
 import org.netbeans.modules.maven.api.Constants;
 import org.netbeans.modules.maven.api.FileUtilities;
 import org.netbeans.modules.maven.api.NbMavenProject;
 import org.netbeans.modules.maven.api.PluginPropertyUtils;
 import org.netbeans.modules.maven.api.execute.ActiveJ2SEPlatformProvider;
+import org.netbeans.modules.maven.api.execute.RunConfig;
 import org.netbeans.modules.maven.configurations.M2ConfigProvider;
 import org.netbeans.modules.maven.configurations.M2Configuration;
 import org.netbeans.modules.maven.configurations.ProjectProfileHandlerImpl;
@@ -82,6 +85,7 @@
 import org.netbeans.modules.maven.debug.MavenJPDAStart;
 import org.netbeans.modules.maven.embedder.EmbedderFactory;
 import org.netbeans.modules.maven.embedder.MavenEmbedder;
+import org.netbeans.modules.maven.execute.ActionToGoalUtils;
 import org.netbeans.modules.maven.modelcache.MavenProjectCache;
 import org.netbeans.modules.maven.options.MavenSettings;
 import org.netbeans.modules.maven.problems.ProblemReporterImpl;
@@ -139,6 +143,7 @@
                 if (hardReferencingMavenProject) {
                     hardRefProject = prj;
                 }
+                projectVariants.clear();
             }
             ACCESSOR.doFireReload(watcher);
         }
@@ -424,6 +429,48 @@
     }
     
     /**
+     * Variants of the projects, possibly other than the ones with the
+     * <b>active configuration</b>
+     */
+    private Map<ProjectActionContext, Reference<MavenProject>> projectVariants = new WeakHashMap<>();
+    
+    public @NonNull MavenProject getEvaluatedProject(ProjectActionContext ctx) {
+        if (ctx == null) {
+            return getOriginalMavenProject();
+        }
+        ProjectActionContext stripped = 
+                ProjectActionContext.newBuilder(ctx.getProject())
+                    .withProfiles(ctx.getProfiles())
+                    .withProperties(ctx.getProperties())
+                    .context();
+        MavenProject result;
+        
+        synchronized (this) {
+            Reference<MavenProject> ref = projectVariants.get(stripped);
+            if (ref != null) {
+                result = ref.get();
+                if (result != null) {
+                    return result;
+                } else {
+                    projectVariants.remove(stripped);
+                }
+            }
+        }
+        RunConfig runConf = null;
+        if (ctx != null && ctx.getProjectAction() != null) {
+            runConf = ActionToGoalUtils.createRunConfig(ctx.getProjectAction(), this, ctx.getConfiguration(), Lookup.EMPTY);
+        }
+        MavenProject newproject = MavenProjectCache.loadMavenProject(this.getPOMFile(), ctx, runConf);
+        synchronized (this) {
+            Reference<MavenProject> ref = projectVariants.get(stripped);
+            if (ref == null || ref.get() == null) {
+                projectVariants.put(stripped, new SoftReference<>(newproject));
+            }
+        }
+        return newproject;
+    }
+    
+    /**
      * a marginally unreliable, non blocking method for figuring if the model is loaded or not.
      * @return 
      */
diff --git a/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java b/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java
index f90deaf..ecb87cc 100644
--- a/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java
+++ b/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java
@@ -44,6 +44,7 @@
 import org.netbeans.api.progress.aggregate.BasicAggregateProgressFactory;
 import org.netbeans.api.progress.aggregate.ProgressContributor;
 import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectActionContext;
 import org.netbeans.modules.maven.NbMavenProjectImpl;
 import static org.netbeans.modules.maven.api.Bundle.*;
 import org.netbeans.modules.maven.embedder.EmbedderFactory;
@@ -287,6 +288,22 @@
     }
     
     /**
+     * Returns a project evaluated for a certain purpose. The while {@link #getMavenProject}
+     * works with the <b>active configuration</b> and does not apply any action-specific properties,
+     * this method tries to apply mappings, configurations, etc when loading the project model.
+     * <p>
+     * Note that loading an evaluated project may take significant time (comparable to loading
+     * the base project itself). The implementation might optimize if the passed context does not
+     * prescribe different profiles, properties etc than have been used for the default model.
+     * 
+     * @param context the loading context
+     * @return evaluated project
+     */
+    public @NonNull MavenProject getEvaluatedProject(ProjectActionContext context) {
+        return project.getEvaluatedProject(context);
+    }
+    
+    /**
      * a marginally unreliable, non blocking method for figuring if the model is loaded or not.
      * @return 
      */
diff --git a/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java b/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java
index 8b507d5..4029d8b 100644
--- a/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java
+++ b/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java
@@ -43,11 +43,14 @@
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.project.ProjectActionContext;
 import org.netbeans.modules.maven.M2AuxilaryConfigImpl;
+import org.netbeans.modules.maven.api.execute.RunConfig;
 import org.netbeans.modules.maven.configurations.M2Configuration;
 import org.netbeans.modules.maven.embedder.EmbedderFactory;
 import org.netbeans.modules.maven.embedder.MavenEmbedder;
 import org.netbeans.spi.project.AuxiliaryConfiguration;
+import org.netbeans.spi.project.ProjectConfiguration;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
 import org.openide.util.Mutex;
@@ -113,6 +116,14 @@
         return mp;
     }
     
+    public static MavenProject loadMavenProject(final File pomFile, ProjectActionContext context, RunConfig runConf) {
+        if (context == null) {
+            return getMavenProject(pomFile, true);
+        } else {
+            return loadOriginalMavenProject(pomFile, context, runConf);
+        }
+    }
+    
     public static MavenExecutionResult getExecutionResult(MavenProject project) {
         return (MavenExecutionResult) project.getContextValue(CONTEXT_EXECUTION_RESULT);
     }
@@ -137,6 +148,10 @@
             + "Please file a bug report with details about your project and the IDE's log file.\n\n"
     })
     private static @NonNull MavenProject loadOriginalMavenProject(final File pomFile) {
+        return loadOriginalMavenProject(pomFile, null, null);
+    }
+    
+    private static @NonNull MavenProject loadOriginalMavenProject(final File pomFile, ProjectActionContext ctx, RunConfig runConf) {
         long startLoading = System.currentTimeMillis();
         MavenEmbedder projectEmbedder = EmbedderFactory.getProjectEmbedder();
         MavenProject newproject = null;
@@ -147,7 +162,16 @@
         }
         AuxiliaryConfiguration aux = new M2AuxilaryConfigImpl(projectDir, false);
         ActiveConfigurationProvider config = new ActiveConfigurationProvider(projectDir, aux);
-        M2Configuration active = config.getActiveConfiguration();
+        M2Configuration active;
+        
+        active = config.getActiveConfiguration();
+        if (ctx != null && ctx.getConfiguration() != null) {
+            ProjectConfiguration cfg = ctx.getConfiguration();
+            if (cfg instanceof M2Configuration) {
+                active = (M2Configuration)cfg;
+            }
+        }
+        
         MavenExecutionResult res = null;
         try {
             List<String> mavenConfigOpts = Collections.emptyList();
@@ -174,6 +198,12 @@
                     addActiveProfiles.accept(opt, "--activate-profiles=");
                 }
             }
+            if (runConf != null) {
+                req.addActiveProfiles(runConf.getActivatedProfiles());
+            }
+            if (ctx != null && ctx.getProfiles() != null) {
+                req.addActiveProfiles(new ArrayList<>(ctx.getProfiles()));
+            }
 
             req.setPom(pomFile);
             req.setNoSnapshotUpdates(true);
@@ -208,6 +238,17 @@
                 }
             }
             uprops.putAll(createUserPropsForProjectLoading(active.getProperties()));
+            if (ctx != null && ctx.getProperties() != null) {
+                for (String k : ctx.getProperties().keySet()) {
+                    uprops.setProperty(k, ctx.getProperties().get(k));
+                }
+            }
+            if (runConf != null && runConf.getProperties() != null) {
+                Map<? extends String, ? extends String> props = runConf.getProperties();
+                for (String k : props.keySet()) {
+                    uprops.setProperty(k, props.get(k));
+                }
+            }
             req.setUserProperties(uprops);
             res = projectEmbedder.readProjectWithDependencies(req, true);
             newproject = res.getProject();