IDEA-119665 Memory leak in RemoteMavenServer when buildnumber plugin is used

Addressing issue by monitoring shutdown hooks before and after maven execute.
This commit is contained in:
Piotr Wielgolaski
2014-02-11 16:43:35 +04:00
committed by Sergey Evdokimov
parent 34512ba0f4
commit bce543e476
2 changed files with 124 additions and 54 deletions
@@ -166,10 +166,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
mySystemProperties.setProperty("java.home", settings.getProjectJdk());
}
myMavenSettings = buildSettings(FieldAccessor.<SettingsBuilder>get(MavenCli.class, cli, "settingsBuilder"),
settings,
mySystemProperties,
FieldAccessor.<Properties>get(cliRequestClass, cliRequest, "userProperties"));
myMavenSettings =
buildSettings(FieldAccessor.<SettingsBuilder>get(MavenCli.class, cli, "settingsBuilder"), settings, mySystemProperties,
FieldAccessor.<Properties>get(cliRequestClass, cliRequest, "userProperties"));
myLocalRepository = createLocalRepository();
}
@@ -177,8 +176,7 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
private static Settings buildSettings(SettingsBuilder builder,
MavenServerSettings settings,
Properties systemProperties,
Properties userProperties)
throws RemoteException {
Properties userProperties) throws RemoteException {
SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
settingsRequest.setGlobalSettingsFile(settings.getGlobalSettingsFile());
settingsRequest.setUserSettingsFile(settings.getUserSettingsFile());
@@ -208,20 +206,22 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
@SuppressWarnings({"unchecked"})
public <T> T getComponent(Class<T> clazz, String roleHint) {
try {
return (T) myContainer.lookup(clazz.getName(), roleHint);
} catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
try {
return (T)myContainer.lookup(clazz.getName(), roleHint);
}
catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings({"unchecked"})
public <T> T getComponent(Class<T> clazz) {
try {
return (T) myContainer.lookup(clazz.getName());
} catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
try {
return (T)myContainer.lookup(clazz.getName());
}
catch (ComponentLookupException e) {
throw new RuntimeException(e);
}
}
private ArtifactRepository createLocalRepository() {
@@ -283,9 +283,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
throws RemoteException, MavenServerProcessCanceledException {
DependencyTreeResolutionListener listener = new DependencyTreeResolutionListener(myConsoleWrapper);
MavenExecutionResult result = doResolveProject(file,
new ArrayList<String>(activeProfiles),
Arrays.<ResolutionListener>asList(listener));
MavenExecutionResult result =
doResolveProject(file, new ArrayList<String>(activeProfiles), Arrays.<ResolutionListener>asList(listener));
return createExecutionResult(file, result, listener.getRootNode());
}
@@ -331,7 +330,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
public MavenExecutionResult doResolveProject(@NotNull final File file,
@NotNull final List<String> activeProfiles,
final List<ResolutionListener> listeners) throws RemoteException {
final MavenExecutionRequest request = createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList());
final MavenExecutionRequest request =
createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList());
final AtomicReference<MavenExecutionResult> ref = new AtomicReference<MavenExecutionResult>();
@@ -395,7 +395,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
return ref.get();
}
/** adapted from {@link org.apache.maven.DefaultMaven#doExecute(org.apache.maven.execution.MavenExecutionRequest)} */
/**
* adapted from {@link org.apache.maven.DefaultMaven#doExecute(org.apache.maven.execution.MavenExecutionRequest)}
*/
private void loadExtensions(MavenProject project, List<Exception> exceptions) {
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
Collection<AbstractMavenLifecycleParticipant> lifecycleParticipants = getLifecycleParticipants(Arrays.asList(project));
@@ -420,7 +422,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
}
}
/** adapted from {@link org.apache.maven.DefaultMaven#getLifecycleParticipants(java.util.Collection)} */
/**
* adapted from {@link org.apache.maven.DefaultMaven#getLifecycleParticipants(java.util.Collection)}
*/
private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants(Collection<MavenProject> projects) {
Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = new LinkedHashSet<AbstractMavenLifecycleParticipant>();
@@ -501,14 +505,14 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
}
private static MavenExecutionResult handleException(Throwable e) {
if (e instanceof Error) throw (Error) e;
if (e instanceof Error) throw (Error)e;
return new MavenExecutionResult(null, Collections.singletonList((Exception) e));
return new MavenExecutionResult(null, Collections.singletonList((Exception)e));
}
@NotNull
public File getLocalRepositoryFile() {
return new File(myLocalRepository.getBasedir());
return new File(myLocalRepository.getBasedir());
}
@NotNull
@@ -522,13 +526,10 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
MavenProject mavenProject = result.getMavenProject();
if (mavenProject == null) return new MavenServerExecutionResult(null, problems, unresolvedArtifacts);
MavenModel model = MavenModelConverter.convertModel(mavenProject.getModel(),
mavenProject.getCompileSourceRoots(),
mavenProject.getTestCompileSourceRoots(),
mavenProject.getArtifacts(),
(rootNode == null ? Collections.emptyList() : rootNode.getChildren()),
mavenProject.getExtensionArtifacts(),
getLocalRepositoryFile());
MavenModel model = MavenModelConverter
.convertModel(mavenProject.getModel(), mavenProject.getCompileSourceRoots(), mavenProject.getTestCompileSourceRoots(),
mavenProject.getArtifacts(), (rootNode == null ? Collections.emptyList() : rootNode.getChildren()),
mavenProject.getExtensionArtifacts(), getLocalRepositoryFile());
RemoteNativeMavenProjectHolder holder = new RemoteNativeMavenProjectHolder(mavenProject);
try {
@@ -540,8 +541,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
Collection<String> activatedProfiles = collectActivatedProfiles(mavenProject);
MavenServerExecutionResult.ProjectData data = new MavenServerExecutionResult.ProjectData(
model, MavenModelConverter.convertToMap(mavenProject.getModel()), holder, activatedProfiles);
MavenServerExecutionResult.ProjectData data =
new MavenServerExecutionResult.ProjectData(model, MavenModelConverter.convertToMap(mavenProject.getModel()), holder,
activatedProfiles);
return new MavenServerExecutionResult(data, problems, unresolvedArtifacts);
}
@@ -618,8 +620,7 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
Set<Artifact> res = getComponent(ArtifactResolver.class)
.resolveTransitively(toResolve, project, Collections.EMPTY_MAP, myLocalRepository, convertRepositories(remoteRepositories),
getComponent(ArtifactMetadataSource.class))
.getArtifacts();
getComponent(ArtifactMetadataSource.class)).getArtifacts();
return MavenModelConverter.convertArtifacts(res, new THashMap<Artifact, MavenArtifact>(), getLocalRepositoryFile());
}
@@ -653,7 +654,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
mavenPlugin.setDependencies(pluginFromProject.getDependencies());
}
final MavenExecutionRequest request = createRequest(null, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList());
final MavenExecutionRequest request =
createRequest(null, Collections.<String>emptyList(), Collections.<String>emptyList(), Collections.<String>emptyList());
DefaultMaven maven = (DefaultMaven)getComponent(Maven.class);
RepositorySystemSession repositorySystemSession = maven.newRepositorySession(request);
@@ -672,8 +674,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
List<MavenArtifact> res = new ArrayList<MavenArtifact>();
for (org.sonatype.aether.artifact.Artifact artifact : nlg.getArtifacts(true)) {
if (!Comparing.equal(artifact.getArtifactId(), plugin.getArtifactId())
|| !Comparing.equal(artifact.getGroupId(), plugin.getGroupId())) {
if (!Comparing.equal(artifact.getArtifactId(), plugin.getArtifactId()) ||
!Comparing.equal(artifact.getGroupId(), plugin.getGroupId())) {
res.add(MavenModelConverter.convertArtifact(RepositoryUtils.toArtifact(artifact), getLocalRepositoryFile()));
}
}
@@ -703,7 +705,7 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
}
public void resolve(@NotNull final Artifact artifact, @NotNull final List<ArtifactRepository> repos)
throws ArtifactResolutionException, ArtifactNotFoundException {
throws ArtifactResolutionException, ArtifactNotFoundException {
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setRemoteRepositories(repos);
@@ -733,11 +735,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
}
private Artifact createArtifact(MavenArtifactInfo info) {
return getComponent(ArtifactFactory.class).createArtifactWithClassifier(info.getGroupId(),
info.getArtifactId(),
info.getVersion(),
info.getPackaging(),
info.getClassifier());
return getComponent(ArtifactFactory.class)
.createArtifactWithClassifier(info.getGroupId(), info.getArtifactId(), info.getVersion(), info.getPackaging(), info.getClassifier());
}
@NotNull
@@ -749,8 +748,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
@NotNull List<String> selectedProjects,
boolean alsoMake,
boolean alsoMakeDependents) throws RemoteException, MavenServerProcessCanceledException {
MavenExecutionResult result = doExecute(file, new ArrayList<String>(activeProfiles), new ArrayList<String>(inactiveProfiles), goals,
selectedProjects, alsoMake, alsoMakeDependents);
MavenExecutionResult result =
doExecute(file, new ArrayList<String>(activeProfiles), new ArrayList<String>(inactiveProfiles), goals, selectedProjects, alsoMake,
alsoMakeDependents);
return createExecutionResult(file, result, null);
}
@@ -778,12 +778,18 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
}
}
Maven maven = getComponent(Maven.class);
org.apache.maven.execution.MavenExecutionResult executionResult = maven.execute(request);
org.apache.maven.execution.MavenExecutionResult executionResult = safeExecute(request, getComponent(Maven.class));
return new MavenExecutionResult(executionResult.getProject(), filterExceptions(executionResult.getExceptions()));
}
private org.apache.maven.execution.MavenExecutionResult safeExecute(MavenExecutionRequest request, Maven maven) throws RemoteException {
MavenLeakDetector detector = new MavenLeakDetector().mark();
org.apache.maven.execution.MavenExecutionResult result = maven.execute(request);
detector.check();
return result;
}
private static List<Exception> filterExceptions(List<Throwable> list) {
for (Throwable throwable : list) {
if (!(throwable instanceof Exception)) {
@@ -897,8 +903,7 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
new DefaultProfileInjector().injectProfile(nativeModel, each, null, null);
}
return new ProfileApplicationResult(MavenModelConverter.convertModel(nativeModel, null),
collectProfilesIds(activatedProfiles));
return new ProfileApplicationResult(MavenModelConverter.convertModel(nativeModel, null), collectProfilesIds(activatedProfiles));
}
private static Model doInterpolate(Model result, File basedir) throws RemoteException {
@@ -943,9 +948,7 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven
return new ProfileActivator[0];
}
return new ProfileActivator[]{new MyFileProfileActivator(basedir),
sysPropertyActivator,
new JdkPrefixProfileActivator(),
return new ProfileActivator[]{new MyFileProfileActivator(basedir), sysPropertyActivator, new JdkPrefixProfileActivator(),
new OperatingSystemProfileActivator()};
}
@@ -0,0 +1,67 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed 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.
*/
package org.jetbrains.idea.maven.server;
import com.intellij.util.ReflectionUtil;
import java.rmi.RemoteException;
import java.util.IdentityHashMap;
import java.util.Map;
public class MavenLeakDetector {
private IdentityHashMap<Thread, Thread> markedHooks = new IdentityHashMap<Thread, Thread>();
public MavenLeakDetector mark() {
markShutdownHooks();
return this;
}
private void markShutdownHooks() {
markedHooks.putAll(getShutdownHooks());
}
public void check() throws RemoteException {
checkShutdownHooks();
}
private void checkShutdownHooks() throws RemoteException {
IdentityHashMap<Thread, Thread> checkedHooks = new IdentityHashMap<Thread, Thread>(getShutdownHooks());
for (Thread t : markedHooks.values()) {
checkedHooks.remove(t);
}
for (Thread t : checkedHooks.values()) {
removeHook(t);
}
}
private void removeHook(Thread thread) throws RemoteException {
Runtime.getRuntime().removeShutdownHook(thread);
Maven3ServerGlobals.getLogger().print(String.format("ShutdownHook[%s] was removed to avoid memory leak", thread));
}
private Map<Thread, Thread> getShutdownHooks() {
Class clazz = null;
try {
clazz = Class.forName("java.lang.ApplicationShutdownHooks");
}
catch (ClassNotFoundException e) {
// we can ignore this one
}
return ReflectionUtil.getField(clazz, null, Map.class, "hooks");
}
}