From 594d4d47d289610099ee726489d929e7c9dbf935 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 8 Aug 2011 20:49:30 +0200 Subject: [PATCH] 'possible VM hang' warning on hotswap --- .../settings/DebuggerHotswapConfigurable.java | 5 ++ .../debugger/settings/DebuggerSettings.java | 2 + .../intellij/debugger/ui/HotSwapUIImpl.java | 46 ++++++++++++++++++- .../debugger/ui/RunHotswapDialog.java | 19 ++++++-- .../src/messages/DebuggerBundle.properties | 3 ++ 5 files changed, 70 insertions(+), 5 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java index ab4b831b9548..a40070aba2e0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerHotswapConfigurable.java @@ -26,6 +26,7 @@ import java.awt.*; public class DebuggerHotswapConfigurable implements SearchableConfigurable { private JCheckBox myHotswapInBackground; private JCheckBox myCbCompileBeforeHotswap; + private JCheckBox myCbHangWarningEnabled; private JRadioButton myRbAlways; private JRadioButton myRbNever; private JRadioButton myRbAsk; @@ -34,6 +35,7 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { final DebuggerSettings settings = DebuggerSettings.getInstance(); myHotswapInBackground.setSelected(settings.HOTSWAP_IN_BACKGROUND); myCbCompileBeforeHotswap.setSelected(settings.COMPILE_BEFORE_HOTSWAP); + myCbHangWarningEnabled.setSelected(settings.HOTSWAP_HANG_WARNING_ENABLED); if(DebuggerSettings.RUN_HOTSWAP_ALWAYS.equals(settings.RUN_HOTSWAP_AFTER_COMPILE)) { myRbAlways.setSelected(true); @@ -53,6 +55,7 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { private void getSettingsTo(DebuggerSettings settings) { settings.HOTSWAP_IN_BACKGROUND = myHotswapInBackground.isSelected(); settings.COMPILE_BEFORE_HOTSWAP = myCbCompileBeforeHotswap.isSelected(); + settings.HOTSWAP_HANG_WARNING_ENABLED = myCbHangWarningEnabled.isSelected(); if (myRbAlways.isSelected()) { settings.RUN_HOTSWAP_AFTER_COMPILE = DebuggerSettings.RUN_HOTSWAP_ALWAYS; @@ -97,12 +100,14 @@ public class DebuggerHotswapConfigurable implements SearchableConfigurable { final JPanel panel = new JPanel(new GridBagLayout()); myCbCompileBeforeHotswap = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.compile.before.hotswap")); + myCbHangWarningEnabled = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.enable.vm.hang.warning")); myHotswapInBackground = new JCheckBox(DebuggerBundle.message("label.debugger.hotswap.configurable.hotswap.background")); myRbAlways = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.always")); myRbNever = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.never")); myRbAsk = new JRadioButton(DebuggerBundle.message("label.debugger.hotswap.configurable.ask")); panel.add(myCbCompileBeforeHotswap, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0)); + panel.add(myCbHangWarningEnabled, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0)); panel.add(myHotswapInBackground, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 0), 0, 0)); int cbLeftOffset = 0; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java index 996c87656825..274fff673938 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java @@ -64,6 +64,7 @@ public class DebuggerSettings implements JDOMExternalizable, NamedComponent, Clo public String EVALUATION_DIALOG_TYPE; public String RUN_HOTSWAP_AFTER_COMPILE; public boolean COMPILE_BEFORE_HOTSWAP; + public boolean HOTSWAP_HANG_WARNING_ENABLED = true; public volatile boolean WATCH_RETURN_VALUES = false; public volatile boolean AUTO_VARIABLES_MODE = false; @@ -145,6 +146,7 @@ public class DebuggerSettings implements JDOMExternalizable, NamedComponent, Clo SKIP_CONSTRUCTORS == secondSettings.SKIP_CONSTRUCTORS && SKIP_GETTERS == secondSettings.SKIP_GETTERS && COMPILE_BEFORE_HOTSWAP == secondSettings.COMPILE_BEFORE_HOTSWAP && + HOTSWAP_HANG_WARNING_ENABLED == secondSettings.HOTSWAP_HANG_WARNING_ENABLED && (RUN_HOTSWAP_AFTER_COMPILE != null ? RUN_HOTSWAP_AFTER_COMPILE.equals(secondSettings.RUN_HOTSWAP_AFTER_COMPILE) : secondSettings.RUN_HOTSWAP_AFTER_COMPILE == null) && DebuggerUtilsEx.filterEquals(mySteppingFilters, secondSettings.mySteppingFilters); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java index b1eccfb89f8d..15a95aa41bbd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.debugger.ui; +import com.intellij.CommonBundle; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.impl.DebuggerSession; @@ -32,12 +33,16 @@ import com.intellij.openapi.compiler.CompilerTopics; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiDocumentManager; +import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -111,6 +116,19 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{ myListeners.remove(listener); } + private boolean shouldDisplayHangWarning(DebuggerSettings settings, List sessions) { + if (!settings.HOTSWAP_HANG_WARNING_ENABLED) { + return false; + } + // todo: return false if yourkit agent is inactive + for (DebuggerSession session : sessions) { + if (session.isPaused()) { + return true; + } + } + return false; + } + private void hotSwapSessions(final List sessions) { final boolean shouldAskBeforeHotswap = myAskBeforeHotswap; myAskBeforeHotswap = true; @@ -118,7 +136,10 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{ // need this because search with PSI is perormed during hotswap PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - final String runHotswap = DebuggerSettings.getInstance().RUN_HOTSWAP_AFTER_COMPILE; + final DebuggerSettings settings = DebuggerSettings.getInstance(); + final String runHotswap = settings.RUN_HOTSWAP_AFTER_COMPILE; + final boolean shouldDisplayHangWarning = shouldDisplayHangWarning(settings, sessions); + if (shouldAskBeforeHotswap && DebuggerSettings.RUN_HOTSWAP_NEVER.equals(runHotswap)) { return; } @@ -139,13 +160,34 @@ public class HotSwapUIImpl extends HotSwapUI implements ProjectComponent{ application.invokeLater(new Runnable() { public void run() { if (shouldAskBeforeHotswap && !DebuggerSettings.RUN_HOTSWAP_ALWAYS.equals(runHotswap)) { - final RunHotswapDialog dialog = new RunHotswapDialog(myProject, sessions); + final RunHotswapDialog dialog = new RunHotswapDialog(myProject, sessions, shouldDisplayHangWarning); dialog.show(); if (!dialog.isOK()) { return; } modifiedClasses.keySet().retainAll(dialog.getSessionsToReload()); } + else { + if (shouldDisplayHangWarning) { + final int answer = Messages.showCheckboxMessageDialog( + DebuggerBundle.message("hotswap.dialog.hang.warning"), + DebuggerBundle.message("hotswap.dialog.title"), + new String[]{CommonBundle.getContinueButtonText(), CommonBundle.getCancelButtonText()}, + CommonBundle.message("dialog.options.do.not.show"), + false, 1, 1, Messages.getWarningIcon(), + new PairFunction() { + @Override + public Integer fun(Integer exitCode, JCheckBox cb) { + settings.HOTSWAP_HANG_WARNING_ENABLED = !cb.isSelected(); + return exitCode; + } + } + ); + if (answer == DialogWrapper.CANCEL_EXIT_CODE) { + return; + } + } + } if (!modifiedClasses.isEmpty()) { final HotSwapProgressImpl progress = new HotSwapProgressImpl(myProject); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java index 7172f4f0bf6a..5e0cbeba3862 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/RunHotswapDialog.java @@ -15,15 +15,16 @@ */ package com.intellij.debugger.ui; +import com.intellij.CommonBundle; +import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.DebuggerBundle; import com.intellij.ide.util.ElementsChooser; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MultiLineLabelUI; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.ui.OptionsDialog; import com.intellij.util.ui.UIUtil; -import com.intellij.CommonBundle; import javax.swing.*; import java.awt.*; @@ -41,9 +42,11 @@ import java.util.List; public class RunHotswapDialog extends OptionsDialog { private final JPanel myPanel; private final ElementsChooser myElementsChooser; + private final boolean myDisplayHangWarning; - public RunHotswapDialog(Project project, java.util.List sessions) { + public RunHotswapDialog(Project project, List sessions, boolean displayHangWarning) { super(project); + myDisplayHangWarning = displayHangWarning; myPanel = new JPanel(new BorderLayout()); final List items = new ArrayList(sessions.size()); for (DebuggerSession session : sessions) { @@ -110,6 +113,16 @@ public class RunHotswapDialog extends OptionsDialog { label.setIcon(icon); label.setIconTextGap(7); } + if (myDisplayHangWarning) { + final JLabel warningLabel = new JLabel(DebuggerBundle.message("hotswap.dialog.hang.warning")); + warningLabel.setUI(new MultiLineLabelUI()); + final Icon warningIcon = UIUtil.getWarningIcon(); + if (warningIcon != null) { + warningLabel.setIcon(warningIcon); + warningLabel.setIconTextGap(7); + } + panel.add(warningLabel, BorderLayout.SOUTH); + } return panel; } diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index e019ffbafaf3..669a8d191854 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -207,6 +207,7 @@ label.debugger.launching.configurable.hide.window=Hide debug &window on process label.debugger.focusAppOnBreakpoint=Focus application on breakpoint label.debugger.hotswap.configurable.hotswap.background=Reload classes in &background label.debugger.hotswap.configurable.compile.before.hotswap=Make project before reloading classes +label.debugger.hotswap.configurable.enable.vm.hang.warning=Enable 'JVM will hang' warning label.debugger.general.configurable.tooltips.delay=&Value tooltips delay (ms): label.debugger.hotswap.configurable.reload.classes=Reload classes after compilation: label.debugger.hotswap.configurable.always=&Always @@ -287,6 +288,8 @@ position.highlighter.stripe.tooltip=Execution line hotswap.dialog.title.with.session=Reload Changed Classes for {0} hotswap.dialog.title=Reload Changed Classes hotswap.dialog.run.prompt=Some classes have been changed. Reload changed classes now? +hotswap.dialog.hang.warning=JVM is currently suspended.\nClasses reloading with active third-party JVM agents may cause the JVM to hang. +hotswap.dialog.hang.question=Would you like to reload changed classes anyway? evaluate.statement.dialog.title=Code Fragment Evaluation label.evaluation.dialog.statements=Statements to &evaluate: action.evaluate.statement.dialog.switch.mode.description=Expression &Mode