diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java index 0a4b52e81706..42aa109394c6 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java @@ -166,10 +166,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven mySystemProperties.setProperty("java.home", settings.getProjectJdk()); } - myMavenSettings = buildSettings(FieldAccessor.get(MavenCli.class, cli, "settingsBuilder"), - settings, - mySystemProperties, - FieldAccessor.get(cliRequestClass, cliRequest, "userProperties")); + myMavenSettings = + buildSettings(FieldAccessor.get(MavenCli.class, cli, "settingsBuilder"), settings, mySystemProperties, + FieldAccessor.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 getComponent(Class 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 getComponent(Class 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(activeProfiles), - Arrays.asList(listener)); + MavenExecutionResult result = + doResolveProject(file, new ArrayList(activeProfiles), Arrays.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 activeProfiles, final List listeners) throws RemoteException { - final MavenExecutionRequest request = createRequest(file, activeProfiles, Collections.emptyList(), Collections.emptyList()); + final MavenExecutionRequest request = + createRequest(file, activeProfiles, Collections.emptyList(), Collections.emptyList()); final AtomicReference ref = new AtomicReference(); @@ -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 exceptions) { ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); Collection 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 getLifecycleParticipants(Collection projects) { Collection lifecycleListeners = new LinkedHashSet(); @@ -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 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 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(), getLocalRepositoryFile()); } @@ -653,7 +654,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven mavenPlugin.setDependencies(pluginFromProject.getDependencies()); } - final MavenExecutionRequest request = createRequest(null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + final MavenExecutionRequest request = + createRequest(null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); DefaultMaven maven = (DefaultMaven)getComponent(Maven.class); RepositorySystemSession repositorySystemSession = maven.newRepositorySession(request); @@ -672,8 +674,8 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven List res = new ArrayList(); 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 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 selectedProjects, boolean alsoMake, boolean alsoMakeDependents) throws RemoteException, MavenServerProcessCanceledException { - MavenExecutionResult result = doExecute(file, new ArrayList(activeProfiles), new ArrayList(inactiveProfiles), goals, - selectedProjects, alsoMake, alsoMakeDependents); + MavenExecutionResult result = + doExecute(file, new ArrayList(activeProfiles), new ArrayList(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 filterExceptions(List 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()}; } diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java new file mode 100644 index 000000000000..15899e7aa38f --- /dev/null +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java @@ -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 markedHooks = new IdentityHashMap(); + + public MavenLeakDetector mark() { + markShutdownHooks(); + return this; + } + + private void markShutdownHooks() { + markedHooks.putAll(getShutdownHooks()); + } + + public void check() throws RemoteException { + checkShutdownHooks(); + } + + private void checkShutdownHooks() throws RemoteException { + IdentityHashMap checkedHooks = new IdentityHashMap(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 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"); + } + +}