This is an automated email from the ASF dual-hosted git repository.

sdedic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new ad99e85b26 #5978: Maven/priming optimization (#5998)
ad99e85b26 is described below

commit ad99e85b260eb029462b4c3ae2cef022b1541b61
Author: Svatopluk Dedic <[email protected]>
AuthorDate: Wed Jun 14 09:25:44 2023 -0700

    #5978: Maven/priming optimization (#5998)
    
    #5978: priming builds are serialized, and check the updated model before 
maven exec
---
 .../netbeans/modules/nbcode/integration/layer.xml  |   9 ++
 .../modules/nbcode/integration/maven.properties    |  19 +++
 .../modules/java/lsp/server/protocol/Server.java   |   7 +-
 .../lsp/server/protocol/WorkspaceServiceImpl.java  |   3 +
 .../netbeans/modules/maven/NbMavenProjectImpl.java |  27 +++-
 .../maven/problems/MavenModelProblemsProvider.java | 149 +++++++++++++++------
 .../maven/problems/ProblemReporterImpl.java        |  18 +++
 .../modules/maven/problems/SanityBuildAction.java  |  43 ++++--
 8 files changed, 216 insertions(+), 59 deletions(-)

diff --git 
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
 
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
index 9bd333789a..44b70b59dd 100644
--- 
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
+++ 
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/layer.xml
@@ -21,6 +21,15 @@
 -->
 <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" 
"http://www.netbeans.org/dtds/filesystem-1_2.dtd";>
 <filesystem>
+    <folder name="Preferences">
+        <folder name="org">
+            <folder name="netbeans">
+                <folder name="modules">
+                    <file name="maven.properties" url="maven.properties"/>
+                </folder>
+            </folder>
+        </folder>
+    </folder>
     <folder name="Services">
         <folder name="NBLS">
             <file name="general-node-commands.instance">
diff --git 
a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
 
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
new file mode 100644
index 0000000000..aca4699843
--- /dev/null
+++ 
b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+primingBuild.snapshot.goals=install
+primingBuild.regular.goals=install
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
index d4768d2a09..3cb748b10c 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
@@ -437,6 +437,8 @@ public final class Server {
                 return CompletableFuture.completedFuture(new Project[0]);
             }
             CompletableFuture<Project[]> f = new CompletableFuture<>();
+            LOG.log(Level.FINER, "Asked to open project(s): {0}", 
Arrays.asList(projectCandidates));
+            LOG.log(Level.FINER, "Caller:", new Throwable());
             SERVER_INIT_RP.post(() -> {
                 asyncOpenSelectedProjects0(f, projectCandidates, addWorkspace, 
false);
             });
@@ -612,7 +614,7 @@ public final class Server {
             List<Project> toOpen = new ArrayList<>();
             Map<Project, CompletableFuture<Void>> local = new HashMap<>();
             synchronized (this) {
-                LOG.log(Level.FINER, "{0}: Asked to open project(s): {1}", new 
Object[]{ id, Arrays.asList(projects) });
+                LOG.log(Level.FINER, "{0}: Opening project(s): {1}", new 
Object[]{ id, Arrays.asList(projects) });
                 for (Project p : projects) {
                     CompletableFuture<Void> pending = beingOpened.get(p);
                     if (pending != null) {
@@ -624,7 +626,7 @@ public final class Server {
                 }
                 beingOpened.putAll(local);
             }
-
+            long t = System.currentTimeMillis();
             LOG.log(Level.FINER, id + ": Opening projects: {0}", 
Arrays.asList(toOpen));
 
             // before the projects are officialy 'opened', try to prime the 
projects
@@ -701,6 +703,7 @@ public final class Server {
                     }
                 }
                 f.complete(prjsRequested);
+                LOG.log(Level.INFO, "{0} projects opened in {1}ms", new 
Object[] { prjsRequested.length, (System.currentTimeMillis() - t) });
             }).exceptionally(e -> {
                 f.completeExceptionally(e);
                 return null;
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
index b009ab7c3b..def77b1d82 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
@@ -60,6 +60,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Supplier;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.prefs.Preferences;
 import java.util.stream.Collectors;
@@ -329,7 +330,9 @@ public final class WorkspaceServiceImpl implements 
WorkspaceService, LanguageCli
                 if (file == null) {
                     return 
CompletableFuture.completedFuture(Collections.emptyList());
                 }
+                long t = System.currentTimeMillis();
                 return 
server.asyncOpenFileOwner(file).thenCompose(this::getTestRoots).thenCompose(testRoots
 -> {
+                    LOG.log(Level.INFO, "Project {2}: {0} test roots opened in 
{1}ms", new Object[] { testRoots.size(), (System.currentTimeMillis() - t), 
file});
                     BiFunction<FileObject, 
Collection<TestMethodController.TestMethod>, Collection<TestSuiteInfo>> f = 
(fo, methods) -> {
                         String url = Utils.toUri(fo);
                         Map<String, TestSuiteInfo> suite2infos = new 
LinkedHashMap<>();
diff --git a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java 
b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
index 7d753e2185..d8a0bedca2 100644
--- a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
+++ b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java
@@ -41,6 +41,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
 import java.util.WeakHashMap;
@@ -138,6 +139,8 @@ public final class NbMavenProjectImpl implements Project {
             MavenProject old;
             synchronized (NbMavenProjectImpl.this) {
                 old = project == null ? null : project.get();
+                LOG.log(Level.FINE, "Project {0} reloaded. Old project is: 
{1}, new project {2}", 
+                        new Object[] { prj, System.identityHashCode(old == 
null ? this : old), System.identityHashCode(prj) });
                 if (old != null && MavenProjectCache.isFallbackproject(prj)) {
                     prj.setPackaging(old.getPackaging()); //#229366 preserve 
packaging for broken projects to avoid changing lookup.
                 }
@@ -150,7 +153,7 @@ public final class NbMavenProjectImpl implements Project {
             ACCESSOR.doFireReload(watcher);
             reloadPossibleBrokenModules(old, prj);
         }
-    });
+    }, true);
     private final FileObject fileObject;
     private final FileObject folderFileObject;
     private final File projectFile;
@@ -420,7 +423,7 @@ public final class NbMavenProjectImpl implements Project {
             if (mp == null) {
                 // PENDING: should be the whole project load synchronized ?
                 mp = loadOriginalMavenProject(false);
-                project = new SoftReference<MavenProject>(mp);
+                project = new SoftReference<>(mp);
                 if (hardReferencingMavenProject) {
                     hardRefProject = mp;
                 }
@@ -431,6 +434,20 @@ public final class NbMavenProjectImpl implements Project {
         return mp;
     }
     
+    /**
+     * Returns the original project, or waits for reload task if already 
pending.
+     * @return possibly reloaded Maven project.
+     */
+    public MavenProject getFreshOriginalMavenProject() {
+        if (reloadTask.isFinished()) {
+            return getOriginalMavenProject();
+        } else {
+            LOG.log(Level.FINE, "Asked for project {0} being updated, waiting 
for the refresh to complete.", projectFile);
+            reloadTask.waitFinished();
+            return getOriginalMavenProject();
+        }
+    }
+    
     /**
      * Variants of the projects, possibly other than the ones with the
      * <b>active configuration</b>
@@ -559,7 +576,8 @@ public final class NbMavenProjectImpl implements Project {
     private void reloadPossibleBrokenModules(MavenProject preceding, 
MavenProject p) {
         // restrict to just poms that were marked as broken/incomplete.
         if (!(MavenProjectCache.isFallbackproject(preceding) || 
-            
preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") 
!= Boolean.TRUE)) {
+            // the project is tagged by Boolean.TRUE, if a SanityBuildAction 
was created for it.
+            
preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") 
== Boolean.TRUE)) {
             return;
         }
         // but do not cascade from projects, which are themselves broken.
@@ -578,8 +596,9 @@ public final class NbMavenProjectImpl implements Project {
                 continue;
             }
             // the project may have more problems, more subtle, but now repair 
just total breakage
-            if (!MavenProjectCache.isFallbackproject(child)) {
+            if (!MavenProjectCache.isFallbackproject(child) && 
child.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") != 
Boolean.TRUE) {
                 LOG.log(Level.FINE, "Project for module {0} is not a fallback, 
skipping", modName);
+                continue;
             }
             FileObject dir = FileUtil.toFileObject(modPom.getParentFile());
             if (dir == null) {
diff --git 
a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
 
b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
index 7fb3806f06..6203ce7741 100644
--- 
a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
+++ 
b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java
@@ -72,6 +72,7 @@ import org.openide.util.NbBundle;
 import org.openide.util.RequestProcessor;
 import org.openide.util.lookup.Lookups;
 import org.netbeans.modules.maven.InternalActionDelegate;
+import org.openide.util.Pair;
 
 /**
  * Suggests to run priming build. Also serves as a provider for Priming Build 
action,
@@ -90,10 +91,19 @@ public class MavenModelProblemsProvider implements 
ProjectProblemsProvider, Inte
     
     private final PropertyChangeSupport support = new 
PropertyChangeSupport(this);
     private final Project project;
-    private final AtomicBoolean projectListenerSet = new AtomicBoolean(false);
-    private final AtomicReference<Collection<ProjectProblem>> problemsCache = 
new AtomicReference<Collection<ProjectProblem>>();
     private final PrimingActionProvider primingProvider = new 
PrimingActionProvider();
+
     private ProblemReporterImpl problemReporter;
+
+    // @GuardedBy(this)
+    private Pair<Collection<ProjectProblem>, Boolean> problemsCache = null;
+    // @GuardedBy(this)
+    private boolean projectListenerSet;
+
+    /**
+     * The Maven project that has been processed already.
+     */
+    private Reference<MavenProject> analysedProject = new 
WeakReference<>(null);
     private final PropertyChangeListener projectListener = new 
PropertyChangeListener() {
 
         @Override
@@ -125,6 +135,15 @@ public class MavenModelProblemsProvider implements 
ProjectProblemsProvider, Inte
         return prbs != null ? prbs : Collections.emptyList();
     }
     
+    /**
+     * Flag set during creation of sanity build action. Usable only inside 
synchronized
+     * section of the problem resolver.
+     */
+    private boolean sanityBuildStatus;
+            
+    public boolean isSanityBuildNeeded() {
+        return doGetProblems1(true).second();
+    }
     
     /**
      * Compute problems. If 'sync' is true, the computation is done 
synchronously. Caches results,
@@ -133,70 +152,110 @@ public class MavenModelProblemsProvider implements 
ProjectProblemsProvider, Inte
      * @return project problems.
      */
     Collection<? extends ProjectProblem> doGetProblems(boolean sync) {
-        final MavenProject prj = 
project.getLookup().lookup(NbMavenProject.class).getMavenProject();
+        return doGetProblems1(sync).first();
+    }
+        
+    /**
+     * Analyzes problem, returns list of problems and priming build status. 
The returned {@link Pair}
+     * contains the list of problems and true/false whether the priming build 
seems necessary. The last result
+     * is cached for the given maven model instance. If the project was 
reloaded, the problems will be computed
+     * again for the new project instance. The call might block waiting on the 
pending project reload. If `sync' 
+     * is false, the method will just post in request processor and return 
{@code null}.
+     * 
+     * @param sync if the call should complete synchronously
+     */
+    private Pair<Collection<ProjectProblem>, Boolean> doGetProblems1(boolean 
sync) {
+        final MavenProject updatedPrj = 
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+        Callable<Pair<Collection<ProjectProblem>, Boolean>> c;
+    
         synchronized (this) {
-            LOG.log(Level.FINER, "Called getProblems for {0}", project);
             //lazy adding listener only when someone asks for the problems the 
first time
-            if (projectListenerSet.compareAndSet(false, true)) {
+            if (!projectListenerSet) {
+                projectListenerSet = true;
                 //TODO do we check only when the project is opened?
                 problemReporter = 
project.getLookup().lookup(NbMavenProjectImpl.class).getProblemReporter();
                 assert problemReporter != null;
                 
project.getLookup().lookup(NbMavenProject.class).addPropertyChangeListener(projectListener);
             
             }
-            
+            MavenProject o = analysedProject.get();
+            LOG.log(Level.FINER, "Called getProblems for {0}, analysed = {1}, 
current = {2}", 
+                    new Object[] { project, o == null ? 0 : 
System.identityHashCode(o), System.identityHashCode(updatedPrj) });
             //for non changed project models, no need to recalculate, always 
return the cached value
-            Object wasprocessed = 
prj.getContextValue(MavenModelProblemsProvider.class.getName());
-            if (wasprocessed != null) {
-                Collection<ProjectProblem> cached = problemsCache.get();
-                LOG.log(Level.FINER, "Project was processed, cached is: {0}", 
cached);
+            Object wasprocessed = 
updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
+            if (o == updatedPrj && wasprocessed != null) {
+                Pair<Collection<ProjectProblem>, Boolean> cached = 
problemsCache;
+                LOG.log(Level.FINER, "getProblems: Project was processed, 
cached is: {0}", cached);
                 if (cached != null) {
                     return cached;
                 }
             } 
-            Callable<Collection<? extends ProjectProblem>> c = new 
Callable<Collection<? extends ProjectProblem>>() {
-                @Override
-                public Collection<? extends ProjectProblem> call() throws 
Exception {
-                    Object wasprocessed = 
prj.getContextValue(MavenModelProblemsProvider.class.getName());
-                    if (wasprocessed != null) {
-                        Collection<ProjectProblem> cached = 
problemsCache.get();
-                        LOG.log(Level.FINER, "Project was processed #2, cached 
is: {0}", cached);
+            
+            SanityBuildAction sba = cachedSanityBuild.get();
+            if (sba != null && sba.getPendingResult() == null) {
+                cachedSanityBuild.clear();
+            }
+            c = () -> {
+                // double check, the project may be invalidated during the 
time.
+                MavenProject prj = 
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+                Object wasprocessed2 = 
updatedPrj.getContextValue(MavenModelProblemsProvider.class.getName());
+                synchronized (MavenModelProblemsProvider.this) {
+                    if (o == updatedPrj && wasprocessed2 != null) {
+                        Pair<Collection<ProjectProblem>, Boolean> cached = 
problemsCache;
+                        LOG.log(Level.FINER, "getProblems: Project was 
processed #2, cached is: {0}", cached);
                         if (cached != null) {                            
                             return cached;
                         }
                     } 
-                    List<ProjectProblem> toRet = new ArrayList<>();
-                    MavenExecutionResult res = 
MavenProjectCache.getExecutionResult(prj);
-                    if (res != null && res.hasExceptions()) {
-                        toRet.addAll(reportExceptions(res));
-                    }
-                    //#217286 doArtifactChecks can call FileOwnerQuery and 
attempt to aquire the project mutex.
-                    toRet.addAll(doArtifactChecks(prj));
-                    //mark the project model as checked once and cached
-                    
prj.setContextValue(MavenModelProblemsProvider.class.getName(), new Object());
-                    synchronized(MavenModelProblemsProvider.this) {
-                        LOG.log(Level.FINER, "Project processing finished, 
result is: {0}", toRet);
-                        problemsCache.set(toRet);
-                    }
-                    firePropertyChange();
-                    return toRet;
-                }                
-            };
-            if(sync || Boolean.getBoolean("test.reload.sync")) {
-                try {
-                    return c.call();
-                } catch (Exception ex) {
-                    Exceptions.printStackTrace(ex);
                 }
-            } else {
-                RP.submit(c);
+                int round = 0;
+                List<ProjectProblem> toRet = null;
+                while (round < 3) {
+                    try {
+                        synchronized (MavenModelProblemsProvider.this) {
+                            sanityBuildStatus = false;
+                            toRet = new ArrayList<>();
+                            MavenExecutionResult res = 
MavenProjectCache.getExecutionResult(prj);
+                            if (res != null && res.hasExceptions()) {
+                                toRet.addAll(reportExceptions(res));
+                            }
+                            //#217286 doArtifactChecks can call FileOwnerQuery 
and attempt to aquire the project mutex.
+                            toRet.addAll(doArtifactChecks(prj));
+                            //mark the project model as checked once and cached
+                            
prj.setContextValue(MavenModelProblemsProvider.class.getName(), new Object());
+                            LOG.log(Level.FINER, "getProblems: Project {1} 
processing finished, result is: {0}",
+                                    new Object[] { toRet, prj });
+                            problemsCache = Pair.of(toRet, sanityBuildStatus);
+                            analysedProject = new WeakReference<>(prj);
+                        }
+                        firePropertyChange();
+                        return Pair.of(toRet, sanityBuildStatus);
+                    } catch (ProblemReporterImpl.ArtifactFoundException ex) {
+                        round++;
+                        LOG.log(Level.FINER, "getProblems: Project {1} 
reported missing artifact that actually exists, restarting - {0} round",
+                                new Object[] { round, prj });
+                        // force reload, then wait for the reload to complete
+                        NbMavenProject.fireMavenProjectReload(project);
+                        prj = 
((NbMavenProjectImpl)project).getFreshOriginalMavenProject();
+                    } 
+                }
+                return Pair.of(toRet, sanityBuildStatus);
+            };
+        }
+        if(sync || Boolean.getBoolean("test.reload.sync")) {
+            try {
+                return c.call();
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
             }
+        } else {
+            RP.submit(c);
         }
         
         // indicate that we do not know
-        return null;
+        return Pair.of(null, true);
     }
-
+    
     private void firePropertyChange() {
         support.firePropertyChange(ProjectProblemsProvider.PROP_PROBLEMS, 
null, null);
     }
@@ -245,6 +304,7 @@ public class MavenModelProblemsProvider implements 
ProjectProblemsProvider, Inte
                             //a.getFile should be already normalized
                             SourceForBinaryQuery.Result2 result = 
SourceForBinaryQuery.findSourceRoots2(archiveUrl);
                             if (!result.preferSources() || /* 
SourceForBinaryQuery.EMPTY_RESULT2.preferSources() so: */ 
result.getRoots().length == 0) {
+                                LOG.log(Level.FINE, "Missing nonsibling 
artifact: {0}", art);
                                 missingNonSibling = true;
                             } // else #189442: typically a snapshot dep on 
another project
                         }
@@ -306,13 +366,14 @@ public class MavenModelProblemsProvider implements 
ProjectProblemsProvider, Inte
     public SanityBuildAction createSanityBuildAction() {
         synchronized (this) {
             SanityBuildAction a = cachedSanityBuild.get();
+            sanityBuildStatus = true;
             if (a != null) {
                 Future<ProjectProblemsProvider.Result> r = 
a.getPendingResult();
                 if (r != null) {
                     return a;
                 }
             }
-            a = new SanityBuildAction(project);
+            a = new SanityBuildAction(project, this::isSanityBuildNeeded);
             
project.getLookup().lookup(NbMavenProject.class).getMavenProject().setContextValue("org.netbeans.modules.maven.problems.primingNotDone",
 true);
             cachedSanityBuild = new WeakReference<>(a);
             return a;
diff --git 
a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java 
b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
index def18e0380..575cdda1b8 100644
--- 
a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
+++ 
b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java
@@ -195,12 +195,30 @@ public final class ProblemReporterImpl implements 
ProblemReporter, Comparator<Pr
             //a.getFile should be already normalized but the find() method can 
pull tricks on us.
             //#225008
             File f = FileUtil.normalizeFile(a.getFile());
+            if (f.exists() && f.canRead()) {
+                throw new ArtifactFoundException(a, f);
+            }
             if (missingArtifacts.add(f)) {                
                 LOG.log(Level.FINE, "listening to {0} from {1}", new Object[] 
{f, projectPOMFile});                
                 FileUtil.addFileChangeListener(fcl, f);
             }
         }
     }
+    
+    /**
+     * Indicates that the cached data that report a missing artifact is 
obsolete. 
+     */
+    public static class ArtifactFoundException extends IllegalStateException {
+        private final Artifact artifact;
+        private final File artifactFile;
+
+        public ArtifactFoundException(Artifact artifact, File artifactFile) {
+            this.artifact = artifact;
+            this.artifactFile = artifactFile;
+        }
+    }
+    
+    
 
     public Set<File> getMissingArtifactFiles() {
         synchronized (reports) {
diff --git 
a/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java 
b/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
index c0f88d3347..9c3b0c81de 100644
--- a/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
+++ b/java/maven/src/org/netbeans/modules/maven/problems/SanityBuildAction.java
@@ -20,12 +20,15 @@
 package org.netbeans.modules.maven.problems;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.function.Supplier;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.modules.maven.TestChecker;
 import org.netbeans.modules.maven.api.NbMavenProject;
 import org.netbeans.modules.maven.api.execute.RunConfig.ReactorStyle;
@@ -33,13 +36,16 @@ import org.netbeans.modules.maven.api.execute.RunUtils;
 import org.netbeans.modules.maven.execute.BeanRunConfig;
 import org.netbeans.modules.maven.execute.MavenProxySupport;
 import org.netbeans.modules.maven.execute.MavenProxySupport.ProxyResult;
+import org.netbeans.modules.maven.options.MavenSettings;
 import static org.netbeans.modules.maven.problems.Bundle.*;
+import org.netbeans.spi.project.RootProjectProvider;
 import org.netbeans.spi.project.ui.ProjectProblemResolver;
 import org.netbeans.spi.project.ui.ProjectProblemsProvider;
 import org.openide.execution.ExecutorTask;
 import org.openide.filesystems.FileUtil;
 import org.openide.util.NbBundle;
 import org.openide.util.NbBundle.Messages;
+import org.openide.util.NbPreferences;
 
 /**
  * Corrective action to run some target which can download plugins or parent 
POMs.
@@ -47,11 +53,13 @@ import org.openide.util.NbBundle.Messages;
  * to believe that there really is a problem with their project, not NetBeans.
  */
 @Messages({"ACT_validate=Priming Build",
+            "ACT_PrimingComplete=Priming build was completed",
             "ACT_start_validate=Priming build was started."})
 public class SanityBuildAction implements ProjectProblemResolver {
     private static final Logger LOG = 
Logger.getLogger(SanityBuildAction.class.getName());
     
     private final Project nbproject;
+    private final Supplier<Boolean> checkSupplier;
     
     /**
      * The priming build, which is currently pending or recently completed.
@@ -59,12 +67,14 @@ public class SanityBuildAction implements 
ProjectProblemResolver {
      */
     private volatile CompletableFuture<ProjectProblemsProvider.Result> 
pendingResult;
 
-    public SanityBuildAction(Project nbproject) {
+    public SanityBuildAction(Project nbproject, Supplier<Boolean> 
checkSupplier) {
         this.nbproject = nbproject;
+        this.checkSupplier = checkSupplier;
     }
 
-    public SanityBuildAction(Project nbproject, 
Future<ProjectProblemsProvider.Result> otherResult) {
+    public SanityBuildAction(Project nbproject, Supplier<Boolean> 
checkSupplier, Future<ProjectProblemsProvider.Result> otherResult) {
         this.nbproject = nbproject;
+        this.checkSupplier = checkSupplier;
     }
     
     public Future<ProjectProblemsProvider.Result> getPendingResult() {
@@ -84,22 +94,35 @@ public class SanityBuildAction implements 
ProjectProblemResolver {
             return pendingResult;
         }
         final CompletableFuture<ProjectProblemsProvider.Result> publicResult = 
new CompletableFuture<>();
-        
+
         Runnable toRet = new Runnable() {
             @Override
             public void run() {
+                /**
+                 * From the appearance of the Sanity action, the project's 
state may have changed. In that case the sanity build should not run maven 
again.
+                 */
+                if (!checkSupplier.get()) {
+                    ProjectProblemsProvider.Result r = 
ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.RESOLVED, 
ACT_start_validate());
+                    if (r != null) {
+                        LOG.log(Level.FINE, "Project {0} is OK before sanity 
build action.", nbproject);
+                        publicResult.complete(r);
+                        return;
+                    }
+                }
                 try {
                     LOG.log(Level.FINE, "Configuring sanity build");
                     BeanRunConfig config = new BeanRunConfig();
                     
config.setExecutionDirectory(FileUtil.toFile(nbproject.getProjectDirectory()));
                     NbMavenProject mavenPrj = 
nbproject.getLookup().lookup(NbMavenProject.class);
+                    String goals;
                     if (mavenPrj != null
                             && mavenPrj.getMavenProject().getVersion() != null 
                             && 
mavenPrj.getMavenProject().getVersion().endsWith("SNAPSHOT")) {
-                        config.setGoals(Arrays.asList("--fail-at-end", 
"install")); // NOI18N
+                        goals = 
NbPreferences.forModule(MavenSettings.class).get("primingBuild.snapshot.goals", 
"install");
                     } else {
-                        config.setGoals(Arrays.asList("--fail-at-end", 
"package")); // NOI18N
+                        goals = 
NbPreferences.forModule(MavenSettings.class).get("primingBuild.regular.goals", 
"package");
                     }
+                    config.setGoals(Arrays.asList("--fail-at-end", goals)); // 
NOI18N
                     config.setReactorStyle(ReactorStyle.ALSO_MAKE);
                     config.setProperty(TestChecker.PROP_SKIP_TEST, "true"); 
//priming doesn't need test execution, just compilation
                     config.setProject(nbproject);
@@ -127,13 +150,15 @@ public class SanityBuildAction implements 
ProjectProblemResolver {
                             return;
                         }
                     }
+                    long t = System.currentTimeMillis();
                     LOG.log(Level.FINE, "Executing sanity build: goals = {0}, 
properties = {1}", new Object[] { config.getGoals(), config.getProperties() });
                     ExecutorTask et = RunUtils.run(config);
-                    et.addTaskListener(t -> {
+                    if (et != null) {
+                        et.waitFinished();
                         ProjectProblemsProvider.Result r = 
ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.RESOLVED, 
ACT_start_validate());
-                        LOG.log(Level.FINE, "Sanity build finished.");
+                        LOG.log(Level.FINE, "Sanity build of {0} finished, 
took {1} ms.", new Object[] { nbproject, System.currentTimeMillis() - t});
                         publicResult.complete(r);
-                    });
+                    }
                 } catch (RuntimeException | Error e) {
                     // always report completness, otherwise tasks that wait on 
priming build could block indefinitely.
                     LOG.log(Level.FINE, "Sanity build failed", e);
@@ -153,7 +178,7 @@ public class SanityBuildAction implements 
ProjectProblemResolver {
         MavenModelProblemsProvider.RP.submit(toRet);
         return publicResult;
     }
-
+    
     @Override
     public int hashCode() {
         int hash = SanityBuildAction.class.hashCode();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to