diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java index b632ba2e0..7de8dadb2 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java @@ -187,6 +187,8 @@ T getMojoParameterValue(MavenProject project, String parameter, Class typ */ Settings getSettings() throws CoreException; + Settings getSettings(MavenSettingsLocations locations) throws CoreException; + String getLocalRepositoryPath(); ArtifactRepository getLocalRepository() throws CoreException; @@ -209,6 +211,10 @@ T getMojoParameterValue(MavenProject project, String parameter, Class typ List getPluginArtifactRepositories(boolean injectSettings) throws CoreException; + /** + * @deprecated use {@link #getSettings(MavenSettingsLocations)} instead + */ + @Deprecated(forRemoval = true) Settings buildSettings(String globalSettings, String userSettings) throws CoreException; void writeSettings(Settings settings, OutputStream out) throws CoreException; diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java index a3611683f..4858b3cc9 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java @@ -134,6 +134,8 @@ public interface IMavenConfiguration { */ boolean buildWithNullSchedulingRule(); + MavenSettingsLocations getSettingsLocations(); + static IMavenConfiguration getWorkspaceConfiguration() { MavenPluginActivator activator = MavenPluginActivator.getDefault(); if(activator == null) { diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java new file mode 100644 index 000000000..5a72127b0 --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2024 Christoph Läubrich and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + ********************************************************************************/ + +package org.eclipse.m2e.core.embedder; + +import java.io.File; + + +/** + * This recored encapsulates the combination of a global and a user settings files as defined in + * https://maven.apache.org/settings.html + */ +public record MavenSettingsLocations(File globalSettings, File userSettings) { + +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java index 73e80b336..e58327cc3 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java @@ -15,8 +15,6 @@ package org.eclipse.m2e.core.internal.embedder; -import static org.eclipse.m2e.core.internal.M2EUtils.copyProperties; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -36,6 +34,7 @@ import java.util.Objects; import java.util.Properties; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.osgi.service.component.annotations.Component; @@ -138,6 +137,7 @@ import org.apache.maven.wagon.proxy.ProxyInfo; import org.eclipse.m2e.core.embedder.ICallable; +import org.eclipse.m2e.core.embedder.IComponentLookup; import org.eclipse.m2e.core.embedder.ILocalRepositoryListener; import org.eclipse.m2e.core.embedder.IMaven; import org.eclipse.m2e.core.embedder.IMavenConfiguration; @@ -145,7 +145,9 @@ import org.eclipse.m2e.core.embedder.IMavenExecutionContext; import org.eclipse.m2e.core.embedder.ISettingsChangeListener; import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent; +import org.eclipse.m2e.core.embedder.MavenSettingsLocations; import org.eclipse.m2e.core.internal.IMavenConstants; +import org.eclipse.m2e.core.internal.M2EUtils; import org.eclipse.m2e.core.internal.Messages; import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants; @@ -169,15 +171,9 @@ public class MavenImpl implements IMaven, IMavenConfigurationChangeListener { private PlexusContainerManager containerManager; /** - * Cached parsed settings.xml instance + * Cached parsed settingsCacheMap.xml instance */ - private Settings settings; - - /** File length of cached user settings */ - private long settingsLength; - - /** Last modified timestamp of cached user settings */ - private long settingsTimestamp; + private Map settingsCacheMap = new ConcurrentHashMap<>(); @Override public String getLocalRepositoryPath() { @@ -274,54 +270,13 @@ public ArtifactRepository getLocalRepository() throws CoreException { @Override public Settings getSettings() throws CoreException { - return getSettings(false); + return getSettings(mavenConfiguration.getSettingsLocations()); } - public synchronized Settings getSettings(boolean forceReload) throws CoreException { - // MUST NOT use createRequest! - - File userSettingsFile = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE; - if(mavenConfiguration.getUserSettingsFile() != null) { - userSettingsFile = new File(mavenConfiguration.getUserSettingsFile()); - } - - boolean reload = forceReload || settings == null; - - if(!reload && userSettingsFile != null) { - reload = userSettingsFile.lastModified() != settingsTimestamp || userSettingsFile.length() != settingsLength; - } - - if(reload) { - // TODO: Can't that delegate to buildSettings()? - SettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); - // 440696 guard against ConcurrentModificationException - Properties systemProperties = new Properties(); - copyProperties(systemProperties, System.getProperties()); - request.setSystemProperties(systemProperties); - if(mavenConfiguration.getGlobalSettingsFile() != null) { - request.setGlobalSettingsFile(new File(mavenConfiguration.getGlobalSettingsFile())); - } - if(userSettingsFile != null) { - request.setUserSettingsFile(userSettingsFile); - } - try { - settings = lookup(SettingsBuilder.class).build(request).getEffectiveSettings(); - } catch(SettingsBuildingException ex) { - String msg = "Could not read settings.xml, assuming default values"; - log.error(msg, ex); - /* - * NOTE: This method provides input for various other core functions, just bailing out would make m2e highly - * unusuable. Instead, we fail gracefully and just ignore the broken settings, using defaults. - */ - settings = new Settings(); - } - - if(userSettingsFile != null) { - settingsLength = userSettingsFile.length(); - settingsTimestamp = userSettingsFile.lastModified(); - } - } - return settings; + @Override + public Settings getSettings(MavenSettingsLocations locations) throws CoreException { + MavenSettings cache = settingsCacheMap.computeIfAbsent(locations, key -> new MavenSettings(key, MavenImpl.this)); + return cache.getSettings(); } @Override @@ -372,7 +327,8 @@ public List validateSettings(String settings) { @Override public void reloadSettings() throws CoreException { - Settings reloadedSettings = getSettings(true); + settingsCacheMap.clear(); + Settings reloadedSettings = getSettings(mavenConfiguration.getSettingsLocations()); for(ISettingsChangeListener listener : settingsListeners) { try { listener.settingsChanged(reloadedSettings); @@ -1103,4 +1059,77 @@ public MavenExecutionContext createExecutionContext() { return new MavenExecutionContext(this, null, null); } + private static final class MavenSettings { + private long userSettingsLength; + + private long userSettingsTimestamp; + + private long globalSettingsLength; + + private long globalSettingsTimestamp; + + private MavenSettingsLocations locations; + + private Settings settings; + + private IComponentLookup lookup; + + public MavenSettings(MavenSettingsLocations locations, IComponentLookup lookup) { + this.locations = locations; + this.lookup = lookup; + } + + private synchronized Settings getSettings() throws CoreException { + File global = locations.globalSettings(); + long gs; + long gt; + if(global != null && global.isFile()) { + gs = global.length(); + gt = global.lastModified(); + } else { + gs = -1; + gt = -1; + } + File user = locations.userSettings(); + long us; + long ut; + if(user != null && user.isFile()) { + us = user.length(); + ut = user.lastModified(); + } else { + us = -1; + ut = -1; + } + boolean reload = settings == null || gs != globalSettingsLength || gt != globalSettingsTimestamp + || us != userSettingsLength || ut != userSettingsTimestamp; + if(reload) { + SettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); + Properties systemProperties = new Properties(); + M2EUtils.copyProperties(systemProperties, System.getProperties()); + request.setSystemProperties(systemProperties); + if(global != null) { + request.setGlobalSettingsFile(global); + } + if(user != null) { + request.setUserSettingsFile(user); + } + try { + settings = lookup.lookup(SettingsBuilder.class).build(request).getEffectiveSettings(); + } catch(SettingsBuildingException ex) { + log.error("Could not read settingsCacheMap.xml, assuming default values", ex); + /* + * NOTE: This method provides input for various other core functions, just bailing out would make m2e highly + * unusable. Instead, we fail gracefully and just ignore the broken settingsCacheMap, using defaults. + */ + settings = new Settings(); + } + globalSettingsLength = gs; + globalSettingsTimestamp = gt; + userSettingsLength = us; + userSettingsTimestamp = ut; + } + return settings; + } + } + } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java index 40537fa80..d9d5d479f 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java @@ -13,6 +13,7 @@ package org.eclipse.m2e.core.internal.preferences; +import java.io.File; import java.util.Map; import java.util.Objects; @@ -41,10 +42,12 @@ import org.eclipse.core.runtime.preferences.PreferenceFilterEntry; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor; import org.eclipse.m2e.core.embedder.IMavenConfiguration; import org.eclipse.m2e.core.embedder.IMavenConfigurationChangeListener; import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent; +import org.eclipse.m2e.core.embedder.MavenSettingsLocations; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.internal.MavenPluginActivator; import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory; @@ -206,6 +209,25 @@ public void preferenceChange(PreferenceChangeEvent event) { } } + @Override + public MavenSettingsLocations getSettingsLocations() { + File userSettings; + File globalSettings; + String configSettingsFile = getUserSettingsFile(); + if (configSettingsFile==null) { + userSettings = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE; + } else { + userSettings = new File(configSettingsFile); + } + String configGlobalSettingsFile = getGlobalSettingsFile(); + if(configGlobalSettingsFile == null) { + globalSettings = null; + } else { + globalSettings = new File(configGlobalSettingsFile); + } + return new MavenSettingsLocations(globalSettings, userSettings); + } + @Override public void added(NodeChangeEvent event) { }