Skip to content

Commit

Permalink
Warmup Maven Embedder to improve first-project-creation UX
Browse files Browse the repository at this point in the history
performance:

 - first embedder initialization can take a while, async-profiler
   showed that a big chunk of it is spent within google guice
 - this starts the warmup task early, which solves the problem, since
   this will happen while the user is looking at the wizard
 - the warmup task is a no-op if it was already initialized

cleanup:

 - small jdk 17 renovation
  • Loading branch information
mbien committed Jul 17, 2024
1 parent a6911ed commit 0c8139d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 89 deletions.
2 changes: 1 addition & 1 deletion java/maven.embedder/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# under the License.

is.autoload=true
javac.source=1.8
javac.release=17
javac.compilerargs=-Xlint -Xlint:-serial
release.external/jdom2-2.0.6.1.jar=modules/ext/maven/jdom2-2.0.6.1.jar
release.external/maven-dependency-tree-2.2.jar=modules/ext/maven/maven-dependency-tree-2.2.jar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package org.netbeans.modules.maven.embedder;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.MavenExecutionException;
Expand All @@ -45,7 +45,7 @@ public class DependencyTreeFactory {
@Deprecated
public static DependencyNode createDependencyTree(MavenProject project, MavenEmbedder embedder, String scope) {
try {
return createDependencyTree(project, embedder, Collections.singleton(scope));
return createDependencyTree(project, embedder, List.of(scope));
} catch (MavenExecutionException ex) {
LOG.log(Level.INFO, "Dependency tree scan failed", ex);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,26 @@
*
* @author mkleint
*/
class EmbedderConfiguration {
private final PlexusContainer cont;
private final Properties props;
private final boolean offline;
private final File settingsXml;
private final Properties userprops;

EmbedderConfiguration(PlexusContainer cont, Properties props, Properties userprops, boolean offline, File settingsXml) {
this.cont = cont;
this.props = props;
this.offline = offline;
this.settingsXml = settingsXml;
this.userprops = userprops;
}
record EmbedderConfiguration(PlexusContainer container, Properties systemProps, Properties userProps, boolean offline, File settingsXml) {

Properties getSystemProperties() {
return props;
return systemProps();
}

Properties getUserProperties() {
return userprops;
return userProps();
}

PlexusContainer getContainer() {
return cont;
return container();
}

public boolean isOffline() {
return offline;
return offline();
}

File getSettingsXml() {
return settingsXml;
return settingsXml();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,35 +60,33 @@ public final class EmbedderFactory {

//same prop constant in MavenSettings.java
static final String PROP_DEFAULT_OPTIONS = "defaultOptions";
private static final Set<String> forbidden = new HashSet<String>();
static {
forbidden.add("netbeans.logger.console"); //NOI18N
forbidden.add("java.util.logging.config.class"); //NOI18N
forbidden.add("netbeans.autoupdate.language"); //NOI18N
forbidden.add("netbeans.dirs"); //NOI18N
forbidden.add("netbeans.home"); //NOI18N
forbidden.add("sun.awt.exception.handler"); //NOI18N
forbidden.add("org.openide.TopManager.GUI"); //NOI18N
forbidden.add("org.openide.major.version"); //NOI18N
forbidden.add("netbeans.autoupdate.variant"); //NOI18N
forbidden.add("netbeans.dynamic.classpath"); //NOI18N
forbidden.add("netbeans.autoupdate.country"); //NOI18N
forbidden.add("netbeans.hash.code"); //NOI18N
forbidden.add("org.openide.TopManager"); //NOI18N
forbidden.add("org.openide.version"); //NOI18N
forbidden.add("netbeans.buildnumber"); //NOI18N
forbidden.add("javax.xml.parsers.DocumentBuilderFactory"); //NOI18N
forbidden.add("javax.xml.parsers.SAXParserFactory"); //NOI18N
forbidden.add("rave.build"); //NOI18N
forbidden.add("netbeans.accept_license_class"); //NOI18N
forbidden.add("rave.version"); //NOI18N
forbidden.add("netbeans.autoupdate.version"); //NOI18N
forbidden.add("netbeans.importclass"); //NOI18N
forbidden.add("netbeans.user"); //NOI18N
// forbidden.add("java.class.path");
// forbidden.add("https.nonProxyHosts");

}
private static final Set<String> forbidden = Set.of(
"netbeans.logger.console", //NOI18N
"java.util.logging.config.class", //NOI18N
"netbeans.autoupdate.language", //NOI18N
"netbeans.dirs", //NOI18N
"netbeans.home", //NOI18N
"sun.awt.exception.handler", //NOI18N
"org.openide.TopManager.GUI", //NOI18N
"org.openide.major.version", //NOI18N
"netbeans.autoupdate.variant", //NOI18N
"netbeans.dynamic.classpath", //NOI18N
"netbeans.autoupdate.country", //NOI18N
"netbeans.hash.code", //NOI18N
"org.openide.TopManager", //NOI18N
"org.openide.version", //NOI18N
"netbeans.buildnumber", //NOI18N
"javax.xml.parsers.DocumentBuilderFactory", //NOI18N
"javax.xml.parsers.SAXParserFactory", //NOI18N
"rave.build", //NOI18N
"netbeans.accept_license_class", //NOI18N
"rave.version", //NOI18N
"netbeans.autoupdate.version", //NOI18N
"netbeans.importclass", //NOI18N
"netbeans.user" //NOI18N
// "java.class.path",
// "https.nonProxyHosts"
);

private static final Logger LOG = Logger.getLogger(EmbedderFactory.class.getName());

Expand All @@ -100,31 +98,24 @@ public final class EmbedderFactory {

private static final RequestProcessor RP = new RequestProcessor("Maven Embedder warmup");

private static final RequestProcessor.Task warmupTask = RP.create(new Runnable() {
@Override
public void run() {
//#211158 after being reset, recreate the instance for followup usage.
//makes the performance stats of the project embedder after resetting more predictable
getProjectEmbedder();
}
});
//#211158 after being reset, recreate the instance for followup usage.
//makes the performance stats of the project embedder after resetting more predictable
private static final RequestProcessor.Task warmupTask = RP.create(EmbedderFactory::getProjectEmbedder);

static {
RP.post(new Runnable() {
@Override
public void run() { //#228379
OpenProjects.getDefault().addProjectGroupChangeListener(new ProjectGroupChangeListener() {
@Override
public void projectGroupChanging(ProjectGroupChangeEvent event) {
resetCachedEmbedders();
}

@Override
public void projectGroupChanged(ProjectGroupChangeEvent event) {
}
});
}
RP.post(() -> { //#228379
OpenProjects.getDefault().addProjectGroupChangeListener(new ProjectGroupChangeListener() {
@Override
public void projectGroupChanging(ProjectGroupChangeEvent event) {
resetCachedEmbedders();
}
@Override
public void projectGroupChanged(ProjectGroupChangeEvent event) {}
});
});
// start initialization; guice can take a while the first time it runs
// if something calls getProjectEmbedder() in the mean time, this is becomes a no-op
warmupTask.schedule(100);
}

private EmbedderFactory() {
Expand Down Expand Up @@ -236,7 +227,7 @@ public static void setGroupedMavenHome(ProjectGroup grp, File path) {

static Map<String, String> getCustomGlobalUserProperties() {
//maybe set org.eclipse.aether.ConfigurationProperties.USER_AGENT with netbeans specific value.
Map<String, String> toRet = new HashMap<String, String>();
Map<String, String> toRet = new HashMap<>();
String options = getPreferences().get(PROP_DEFAULT_OPTIONS, "");
try {

Expand Down Expand Up @@ -363,9 +354,7 @@ static Properties cloneStaticProps() {
EmbedderFactory.fillEnvVars(statics);
statics.putAll(excludeNetBeansProperties(System.getProperties()));
}
Properties toRet = new Properties();
toRet.putAll(statics);
return toRet;
return new Properties(statics);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ public final class MavenEmbedder {
settingsDecrypter = plexus.lookup(SettingsDecrypter.class);

VersionResolver vr = plexus.lookup(VersionResolver.class);
if (vr instanceof NbVersionResolver2) {
versionResolver = (NbVersionResolver2)vr;
if (vr instanceof NbVersionResolver2 vr2) {
versionResolver = vr2;
} else {
versionResolver = null;
}
Expand Down Expand Up @@ -454,7 +454,7 @@ public MavenExecutionResult execute(MavenExecutionRequest req) {
*/
public List<Model> createModelLineage(File pom) throws ModelBuildingException {
ModelBuildingResult res = executeModelBuilder(pom);
List<Model> toRet = new ArrayList<Model>();
List<Model> toRet = new ArrayList<>();

for (String id : res.getModelIds()) {
Model m = res.getRawModel(id);
Expand Down Expand Up @@ -550,12 +550,12 @@ public List<String> getLifecyclePhases() {

LifecycleMapping lifecycleMapping = lookupComponent(LifecycleMapping.class);
if (lifecycleMapping != null) {
Set<String> phases = new TreeSet<String>();
Set<String> phases = new TreeSet<>();
Map<String, Lifecycle> lifecycles = lifecycleMapping.getLifecycles();
for (Lifecycle lifecycle : lifecycles.values()) {
phases.addAll(lifecycle.getPhases().keySet());
}
return new ArrayList<String>(phases);
return new ArrayList<>(phases);
}

return Collections.<String>emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.apache.maven.model.resolution.ModelResolver;
import org.apache.maven.model.resolution.UnresolvableModelException;
import org.apache.maven.repository.RepositorySystem;
import org.openide.util.Exceptions;

/**
*
Expand All @@ -44,7 +43,7 @@ class NBRepositoryModelResolver
implements ModelResolver {

private final MavenEmbedder embedder;
private List<ArtifactRepository> remoteRepositories = new ArrayList<ArtifactRepository>();
private List<ArtifactRepository> remoteRepositories = new ArrayList<>();


NBRepositoryModelResolver(MavenEmbedder embedder) {
Expand All @@ -53,7 +52,7 @@ class NBRepositoryModelResolver

private NBRepositoryModelResolver(NBRepositoryModelResolver original) {
this(original.embedder);
this.remoteRepositories = new ArrayList<ArtifactRepository>(original.remoteRepositories);
this.remoteRepositories = new ArrayList<>(original.remoteRepositories);
}

@Override
Expand All @@ -72,10 +71,8 @@ public ModelSource resolveModel(String groupId, String artifactId, String versio
Artifact artifactParent = embedder.lookupComponent(RepositorySystem.class).createProjectArtifact(groupId, artifactId, version);
try {
embedder.resolveArtifact(artifactParent, remoteRepositories, embedder.getLocalRepository());
} catch (ArtifactResolutionException ex) {
} catch (ArtifactResolutionException | ArtifactNotFoundException ex) {
throw new UnresolvableModelException(ex.getMessage(), groupId , artifactId , version );
} catch (ArtifactNotFoundException ex) {
throw new UnresolvableModelException( ex.getMessage(), groupId , artifactId , version );
}

return new FileModelSource(artifactParent.getFile());
Expand Down

0 comments on commit 0c8139d

Please sign in to comment.