diff --git a/bundles/io.openliberty.tools.eclipse.ui/META-INF/MANIFEST.MF b/bundles/io.openliberty.tools.eclipse.ui/META-INF/MANIFEST.MF index f7243b8e..96fdb985 100644 --- a/bundles/io.openliberty.tools.eclipse.ui/META-INF/MANIFEST.MF +++ b/bundles/io.openliberty.tools.eclipse.ui/META-INF/MANIFEST.MF @@ -13,7 +13,9 @@ Export-Package: io.openliberty.tools.eclipse;x-friends:="io.openliberty.tools.ec io.openliberty.tools.eclipse.ui.launch.shortcuts;x-friends:="io.openliberty.tools.eclipse.tests", io.openliberty.tools.eclipse.ui.preferences;x-friends:="io.openliberty.tools.eclipse.tests" Require-Bundle: org.eclipse.ui, - org.eclipse.m2e.maven.runtime + org.eclipse.m2e.maven.runtime, + org.eclipse.jdt.debug.ui, + org.eclipse.jdt.debug Bundle-RequiredExecutionEnvironment: JavaSE-17 Automatic-Module-Name: io.openliberty.tools.eclipse.ui Bundle-ActivationPolicy: lazy diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/DevModeOperations.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/DevModeOperations.java index 200b1b11..ad3a4eee 100644 --- a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/DevModeOperations.java +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/DevModeOperations.java @@ -18,7 +18,6 @@ import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -241,7 +240,7 @@ public void start(IProject iProject, String parms, String javaHomePath, ILaunch // If there is a debugPort, start the job to attach the debugger to the Liberty server JVM. if (debugPort != null) { - debugModeHandler.startDebugAttacher(project, launch, debugPort); + debugModeHandler.startDebugAttacher(project, launch, debugPort, false); } } catch (CommandNotFoundException e) { String msg = "Maven or Gradle command not found for project " + projectName; @@ -356,7 +355,7 @@ public void startInContainer(IProject iProject, String parms, String javaHomePat // If there is a debugPort, start the job to attach the debugger to the Liberty server JVM. if (debugPort != null) { - debugModeHandler.startDebugAttacher(project, launch, debugPort); + debugModeHandler.startDebugAttacher(project, launch, debugPort, false); } } catch (Exception e) { String msg = "An error was detected during the start in container request on project " + projectName; @@ -818,7 +817,7 @@ private void handleStopActionError(String projectName, String baseMsg) { * * @param projectName The name of the project for which the the Liberty plugin stop command is issued. */ - private void issueLPStopCommand(String projectName) { + public void issueLPStopCommand(String projectName) { if (Trace.isEnabled()) { Trace.getTracer().traceEntry(Trace.TRACE_TOOLS, projectName); } @@ -989,6 +988,12 @@ public static Path getMavenIntegrationTestReportPath(String projectPath) { return path; } + public Path getLibertyPluginConfigXmlPath(String projectPath) { + Path path = Paths.get(projectPath, "target", "liberty-plugin-config.xml"); + + return path; + } + /** * Returns the path of the HTML file containing the unit test report. * diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/DebugModeHandler.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/DebugModeHandler.java index 02b81199..2e78ee05 100644 --- a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/DebugModeHandler.java +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/DebugModeHandler.java @@ -12,22 +12,22 @@ *******************************************************************************/ package io.openliberty.tools.eclipse.debug; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.net.ConnectException; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; +import java.util.Scanner; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.Stream; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; @@ -41,16 +41,16 @@ import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.jdi.Bootstrap; import org.eclipse.jdi.TimeoutException; -import org.eclipse.jdt.debug.core.JDIDebugModel; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.JavaRuntime; -import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; import com.sun.jdi.VirtualMachine; import com.sun.jdi.connect.AttachingConnector; @@ -62,9 +62,10 @@ import io.openliberty.tools.eclipse.LibertyDevPlugin; import io.openliberty.tools.eclipse.Project; import io.openliberty.tools.eclipse.Project.BuildType; +import io.openliberty.tools.eclipse.logging.Logger; import io.openliberty.tools.eclipse.logging.Trace; -import io.openliberty.tools.eclipse.messages.Messages; import io.openliberty.tools.eclipse.ui.dashboard.DashboardView; +import io.openliberty.tools.eclipse.ui.launch.LaunchConfigurationHelper; import io.openliberty.tools.eclipse.ui.terminal.ProjectTabController; import io.openliberty.tools.eclipse.ui.terminal.TerminalListener; import io.openliberty.tools.eclipse.utils.ErrorHandler; @@ -95,6 +96,9 @@ public class DebugModeHandler { /** Job status return code indicating that an error took place while attempting to attach the debugger to the JVM. */ public static int JOB_STATUS_DEBUGGER_CONN_ERROR = 1; + /** Instance to this class. */ + private LaunchConfigurationHelper launchConfigHelper = LaunchConfigurationHelper.getInstance(); + /** DevModeOperations instance. */ private DevModeOperations devModeOps; @@ -217,7 +221,7 @@ public String calculateDebugPort(Project project, String inputParms) throws Exce * * @throws Exception */ - public void startDebugAttacher(Project project, ILaunch launch, String debugPort) { + public void startDebugAttacher(Project project, ILaunch launch, String port, boolean readDebugPort) { String projectName = project.getIProject().getName(); Job job = new Job("Attaching Debugger to JVM...") { @@ -228,6 +232,27 @@ protected IStatus run(IProgressMonitor monitor) { return Status.CANCEL_STATUS; } + String debugPort = null; + + if (readDebugPort) { + // Read debug port from server.env. If devmode has restarted the server, it may + // take a few seconds for it to find a new port in the event that the previous port + // is still being held by the OS. + Thread.sleep(5000); + + try { + File serverEnvFile = getServerEnvFile(project); + if (serverEnvFile != null) { + debugPort = readDebugPortFromServerEnv(serverEnvFile); + } + } catch (Exception e) { + Logger.logError("Failure while attempting to read debug port from server.env file", e); + } + } + if (debugPort == null) { + debugPort = port; + } + String portToConnect = waitForSocketActivation(project, DEFAULT_ATTACH_HOST, debugPort, monitor); if (portToConnect == null) { return Status.CANCEL_STATUS; @@ -236,10 +261,14 @@ protected IStatus run(IProgressMonitor monitor) { AttachingConnector connector = getAttachingConnector(); Map map = connector.defaultArguments(); configureConnector(map, DEFAULT_ATTACH_HOST, Integer.parseInt(portToConnect)); - IDebugTarget debugTarget = createRemoteJDTDebugTarget(launch, Integer.parseInt(portToConnect), DEFAULT_ATTACH_HOST, + IDebugTarget debugTarget = createRemoteJDTDebugTarget(launch, project, Integer.parseInt(portToConnect), + DEFAULT_ATTACH_HOST, connector, map); launch.addDebugTarget(debugTarget); + for (IDebugTarget target : launch.getDebugTargets()) { + System.out.println("DebugTarget: " + target.getName()); + } } catch (Exception e) { return new Status(IStatus.ERROR, LibertyDevPlugin.PLUGIN_ID, JOB_STATUS_DEBUGGER_CONN_ERROR, @@ -334,7 +363,7 @@ private void configureConnector(Map map, String host, int port } } - private IDebugTarget createRemoteJDTDebugTarget(ILaunch launch, int remoteDebugPortNum, String hostName, + private IDebugTarget createRemoteJDTDebugTarget(ILaunch launch, Project project, int remoteDebugPortNum, String hostName, AttachingConnector connector, Map map) throws CoreException { if (launch == null || hostName == null || hostName.length() == 0) { return null; @@ -351,8 +380,13 @@ private IDebugTarget createRemoteJDTDebugTarget(ILaunch launch, int remoteDebugP throw new CoreException( new Status(IStatus.ERROR, this.getClass(), IJavaLaunchConfigurationConstants.ERR_CONNECTION_FAILED, "", ex)); } - debugTarget = JDIDebugModel.newDebugTarget(launch, remoteVM, hostName + ":" + remoteDebugPortNum, null, true, false, true); - return debugTarget; + LibertyDebugTarget libertyDebugTarget = new LibertyDebugTarget(launch, remoteVM, hostName + ":" + remoteDebugPortNum, + new RestartDebugger(project, launch, String.valueOf(remoteDebugPortNum))); + + // Add hot code replace listener to listen for hot code replace failure. + libertyDebugTarget.addHotCodeReplaceListener(new LibertyHotCodeReplaceListener()); + + return libertyDebugTarget; } /** @@ -461,64 +495,41 @@ private void openDebugPerspective() { } /** - * Returns the default path of the server.env file after Liberty server deployment. + * Returns the path of the server.env file after Liberty server deployment. * * @param project The project for which this operations is being performed. * - * @return The default path of the server.env file after Liberty server deployment. + * @return The path of the server.env file after Liberty server deployment. * * @throws Exception */ - private Path getServerEnvPath(Project project) throws Exception { - Path basePath = null; + private File getServerEnvFile(Project project) throws Exception { + Project serverProj = getLibertyServerProject(project); String projectPath = serverProj.getPath(); - String projectName = serverProj.getName(); - BuildType buildType = serverProj.getBuildType(); - if (buildType == Project.BuildType.MAVEN) { - basePath = Paths.get(projectPath, "target", "liberty", "wlp", "usr", "servers"); - } else if (buildType == Project.BuildType.GRADLE) { - basePath = Paths.get(projectPath, "build", "wlp", "usr", "servers"); - } else { - throw new Exception("Unexpected project build type: " + buildType + ". Project" + projectName - + "does not appear to be a Maven or Gradle built project."); - } + Path libertyPluginConfigXmlPath = devModeOps.getLibertyPluginConfigXmlPath(projectPath); + + // Read server.env path from liberty-plugin-config.xml + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + DocumentBuilder db = dbf.newDocumentBuilder(); - // Make sure the base path exists. If not return null. - File basePathFile = new File(basePath.toString()); - if (!basePathFile.exists()) { + Document doc = db.parse(libertyPluginConfigXmlPath.toFile()); + doc.getDocumentElement().normalize(); + + NodeList list = doc.getElementsByTagName("serverDirectory"); + Path serverEnvPath = Paths.get(list.item(0).getTextContent(), "server.env"); + + File serverEnvFile = serverEnvPath.toFile(); + // Make sure the server.env path exists. If not return null. + if (!serverEnvFile.exists()) { return null; } - try (Stream matchedStream = Files.find(basePath, 2, (path, basicFileAttribute) -> { - if (basicFileAttribute.isRegularFile()) { - return path.getFileName().toString().equalsIgnoreCase(WLP_SERVER_ENV_FILE_NAME); - } - return false; - });) { - List matchedPaths = matchedStream.collect(Collectors.toList()); - int numberOfFilesFound = matchedPaths.size(); - - if (numberOfFilesFound != 1) { - if (numberOfFilesFound == 0) { - String msg = "Unable to find the server.env file for project " + projectName + "."; - if (Trace.isEnabled()) { - Trace.getTracer().trace(Trace.TRACE_UI, msg); - } - return null; - } else { - String msg = "More than one server.env file was found for project " + projectName - + ". Unable to determine which server.env file to use."; - if (Trace.isEnabled()) { - Trace.getTracer().trace(Trace.TRACE_UI, msg); - } - ErrorHandler.processErrorMessage(NLS.bind(Messages.multiple_server_env, projectName), false); - throw new Exception(msg); - } - } - return matchedPaths.get(0); - } + return serverEnvFile; + } /** @@ -536,19 +547,25 @@ public String readDebugPortFromServerEnv(File serverEnv) throws Exception { String port = null; if (serverEnv.exists()) { - try (BufferedReader reader = new BufferedReader(new FileReader(serverEnv))) { - String line = null; - String lastEntry = null; - while ((line = reader.readLine()) != null) { - if (line.contains(WLP_ENV_DEBUG_ADDRESS)) { - lastEntry = line; - } - } - if (lastEntry != null) { - String[] parts = lastEntry.split("="); - port = parts[1].trim(); + String lastEntry = null; + + Scanner scan = new Scanner(serverEnv); + String line; + + while (scan.hasNextLine()) { + line = scan.nextLine(); + if (line.contains(WLP_ENV_DEBUG_ADDRESS)) { + lastEntry = line; } } + + scan.close(); + + if (lastEntry != null) { + String[] parts = lastEntry.split("="); + port = parts[1].trim(); + } + } return port; @@ -574,7 +591,6 @@ private String waitForSocketActivation(Project project, String host, String port // this timeout value, we could potentially tie it to the "Launch timeout" setting of in the // Eclipse "Debug" preferences. - byte[] handshakeString = "JDWP-Handshake".getBytes(StandardCharsets.US_ASCII); int retryLimit = 180; int envReadInterval = 2; @@ -605,11 +621,8 @@ public void run() { } } - try (Socket socket = new Socket(host, Integer.valueOf(port))) { - socket.getOutputStream().write(handshakeString); + if (socketIsActivated(host, port)) { return port; - } catch (ConnectException ce) { - TimeUnit.SECONDS.sleep(1); } } @@ -617,6 +630,19 @@ public void run() { + ". If the server starts later you might try to manually create a Remote Java Application debug configuration and attach to the server. You can confirm the debug port used in the terminal output looking for a message like 'Liberty debug port: [ 63624 ]'."); } + private boolean socketIsActivated(String host, String port) throws Exception { + byte[] handshakeString = "JDWP-Handshake".getBytes(StandardCharsets.US_ASCII); + + try (Socket socket = new Socket(host, Integer.valueOf(port))) { + socket.getOutputStream().write(handshakeString); + return true; + } catch (ConnectException ce) { + TimeUnit.SECONDS.sleep(1); + } + + return false; + } + /** * Returns the liberty server module project associated with the input project. * @@ -645,4 +671,21 @@ private Project getLibertyServerProject(Project project) throws Exception { private class DataHolder { boolean closed; } + + class RestartDebugger { + + private Project project; + private ILaunch launch; + private String port; + + RestartDebugger(Project project, ILaunch launch, String port) { + this.project = project; + this.launch = launch; + this.port = port; + } + + public void restart(boolean readDebugPort) { + startDebugAttacher(project, launch, port, readDebugPort); + } + } } diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyDebugTarget.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyDebugTarget.java new file mode 100644 index 00000000..744e1cc9 --- /dev/null +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyDebugTarget.java @@ -0,0 +1,54 @@ +package io.openliberty.tools.eclipse.debug; + +import org.eclipse.debug.core.ILaunch; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; + +import io.openliberty.tools.eclipse.debug.DebugModeHandler.RestartDebugger; + +public class LibertyDebugTarget extends JDIDebugTarget { + + private RestartDebugger restartDebugger; + + public LibertyDebugTarget(ILaunch launch, VirtualMachine jvm, String name, RestartDebugger restartDebugger) { + super(launch, jvm, "Liberty Application Debug: " + name, true, true, null, true); + + this.restartDebugger = restartDebugger; + } + + @Override + public void handleVMDeath(VMDeathEvent event) { + System.out.println("VM DEATH!"); + disconnected(); + } + + @Override + public void handleVMDisconnect(VMDisconnectEvent event) { + System.out.println("VM DISCONNECT!"); + disconnected(); + } + + public void restartDebugger(boolean readDebugPort) { + setDisconnecting(false); + if (!isDisconnected()) { + setDisconnected(true); + cleanup(); + + getLaunch().removeDebugTarget(this); + restartDebugger.restart(readDebugPort); + restartDebugger = null; + } + } + + /** + * Updates the state of this target for disconnection from the VM. + */ + @Override + protected void disconnected() { + restartDebugger(true); + } + +} diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceErrorDialog.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceErrorDialog.java new file mode 100644 index 00000000..c8ec52ac --- /dev/null +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceErrorDialog.java @@ -0,0 +1,78 @@ +/******************************************************************************* +* Copyright (c) 2022, 2023 IBM Corporation and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0. +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.tools.eclipse.debug; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.ui.DebugUIMessages; +import org.eclipse.jdt.internal.debug.ui.HotCodeReplaceErrorDialog; +import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; + +public class LibertyHotCodeReplaceErrorDialog extends HotCodeReplaceErrorDialog { + + public LibertyHotCodeReplaceErrorDialog(Shell parentShell, String dialogTitle, String message, IStatus status, String preferenceKey, + String toggleMessage, IPreferenceStore store, IDebugTarget target) { + super(parentShell, dialogTitle, message, status, preferenceKey, toggleMessage, store, target); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createDetailsButton(parent); + getButton(IDialogConstants.OK_ID).setText(DebugUIMessages.HotCodeReplaceErrorDialog_0); + createButton(parent, DISCONNECT_ID, "Refresh Debugger", false); + + blockMnemonicWithoutModifier(getToggleButton()); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int) + */ + @Override + protected void buttonPressed(final int id) { + if (id == DISCONNECT_ID) { + final DebugException[] ex = new DebugException[1]; + final String[] operation = new String[1]; + ex[0] = null; + Runnable r = new Runnable() { + @Override + public void run() { + try { + operation[0] = DebugUIMessages.HotCodeReplaceErrorDialog_6; + ((LibertyDebugTarget) target).restartDebugger(false); + } catch (Exception e) { + IStatus errorStatus = new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), e.getMessage(), e); + ex[0] = new DebugException(errorStatus); + } + } + }; + BusyIndicator.showWhile(getShell().getDisplay(), r); + if (ex[0] != null) { + JDIDebugUIPlugin.statusDialog(NLS.bind(DebugUIMessages.HotCodeReplaceErrorDialog_2, operation), ex[0].getStatus()); + } + okPressed(); + } else { + super.buttonPressed(id); + } + } +} diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceListener.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceListener.java new file mode 100644 index 00000000..1ae223f0 --- /dev/null +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/debug/LibertyHotCodeReplaceListener.java @@ -0,0 +1,159 @@ +/******************************************************************************* +* Copyright (c) 2022, 2023 IBM Corporation and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0. +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* IBM Corporation - initial implementation +*******************************************************************************/ +package io.openliberty.tools.eclipse.debug; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener; +import org.eclipse.jdt.internal.debug.ui.DebugUIMessages; +import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants; +import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; +import org.eclipse.jdt.internal.debug.ui.snippeteditor.ScrapbookLauncher; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +public class LibertyHotCodeReplaceListener implements IJavaHotCodeReplaceListener { + + private LibertyHotCodeReplaceErrorDialog libertyHotCodeReplaceFailedErrorDialog = null; + + private ILabelProvider fLabelProvider = DebugUITools.newDebugModelPresentation(); + + /** + * @see IJavaHotCodeReplaceListener#hotCodeReplaceSucceeded(IJavaDebugTarget) + */ + @Override + public void hotCodeReplaceSucceeded(IJavaDebugTarget target) { + } + + /** + * @see IJavaHotCodeReplaceListener#hotCodeReplaceFailed(IJavaDebugTarget, DebugException) + */ + @Override + public void hotCodeReplaceFailed(final IJavaDebugTarget target, final DebugException exception) { + if ((exception != null + && !JDIDebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_FAILED)) || + ((exception == null) && !JDIDebugUIPlugin.getDefault().getPreferenceStore() + .getBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_NOT_SUPPORTED))) { + return; + } + // do not report errors for snippet editor targets + // that do not support HCR. HCR is simulated by using + // a new class loader for each evaluation + ILaunch launch = target.getLaunch(); + if (launch.getAttribute(ScrapbookLauncher.SCRAPBOOK_LAUNCH) != null) { + if (!target.supportsHotCodeReplace()) { + return; + } + } + final Display display = JDIDebugUIPlugin.getStandardDisplay(); + if (display.isDisposed()) { + return; + } + + String name = null; + try { + name = target.getName(); + } catch (DebugException e) { + name = fLabelProvider.getText(target); + } + final String vmName = name; + final IStatus status; + final String preference; + final String alertMessage; + ILaunchConfiguration config = target.getLaunch().getLaunchConfiguration(); + final String launchName = (config != null ? config.getName() : DebugUIMessages.JavaHotCodeReplaceListener_0); + if (exception == null) { + status = new Status(IStatus.WARNING, JDIDebugUIPlugin.getUniqueIdentifier(), IStatus.WARNING, + DebugUIMessages.JDIDebugUIPlugin_The_target_VM_does_not_support_hot_code_replace_1, null); + preference = IJDIPreferencesConstants.PREF_ALERT_HCR_NOT_SUPPORTED; + alertMessage = DebugUIMessages.JDIDebugUIPlugin_3; + } else { + status = new Status(IStatus.WARNING, JDIDebugUIPlugin.getUniqueIdentifier(), IStatus.WARNING, exception.getMessage(), + exception.getCause()); + preference = IJDIPreferencesConstants.PREF_ALERT_HCR_FAILED; + alertMessage = DebugUIMessages.JDIDebugUIPlugin_1; + } + final String title = DebugUIMessages.JDIDebugUIPlugin_Hot_code_replace_failed_1; + final String message = NLS.bind( + DebugUIMessages.JDIDebugUIPlugin__0__was_unable_to_replace_the_running_code_with_the_code_in_the_workspace__2, + new Object[] { vmName, launchName }); + display.asyncExec(new Runnable() { + @Override + public void run() { + if (display.isDisposed()) { + return; + } + if (libertyHotCodeReplaceFailedErrorDialog != null) { + Shell shell = libertyHotCodeReplaceFailedErrorDialog.getShell(); + if (shell != null && !shell.isDisposed()) { + return; + } + } + Shell shell = JDIDebugUIPlugin.getActiveWorkbenchShell(); + libertyHotCodeReplaceFailedErrorDialog = new LibertyHotCodeReplaceErrorDialog(shell, title, message, status, preference, + alertMessage, + JDIDebugUIPlugin.getDefault().getPreferenceStore(), target) { + @Override + public boolean close() { + libertyHotCodeReplaceFailedErrorDialog = null; + return super.close(); + } + }; + libertyHotCodeReplaceFailedErrorDialog.setBlockOnOpen(false); + libertyHotCodeReplaceFailedErrorDialog.open(); + } + }); + } + + /** + * @see IJavaHotCodeReplaceListener#obsoleteMethods(IJavaDebugTarget) + */ + @Override + public void obsoleteMethods(final IJavaDebugTarget target) { + if (!JDIDebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS)) { + return; + } + final Display display = JDIDebugUIPlugin.getStandardDisplay(); + if (display.isDisposed()) { + return; + } + final String vmName = fLabelProvider.getText(target); + final String dialogTitle = DebugUIMessages.JDIDebugUIPlugin_Obsolete_methods_remain_1; + final String message = NLS.bind(DebugUIMessages.JDIDebugUIPlugin__0__contains_obsolete_methods_1, new Object[] { vmName }); + final IStatus status = new Status(IStatus.WARNING, JDIDebugUIPlugin.getUniqueIdentifier(), IStatus.WARNING, + DebugUIMessages.JDIDebugUIPlugin_Stepping_may_be_hazardous_1, null); + final String toggleMessage = DebugUIMessages.JDIDebugUIPlugin_2; + display.asyncExec(new Runnable() { + @Override + public void run() { + if (display.isDisposed()) { + return; + } + Shell shell = JDIDebugUIPlugin.getActiveWorkbenchShell(); + LibertyHotCodeReplaceErrorDialog dialog = new LibertyHotCodeReplaceErrorDialog(shell, dialogTitle, message, status, + IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS, + toggleMessage, JDIDebugUIPlugin.getDefault().getPreferenceStore(), target); + dialog.setBlockOnOpen(false); + dialog.open(); + } + }); + } + +} diff --git a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/ui/terminal/ProjectTabController.java b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/ui/terminal/ProjectTabController.java index fa8318f3..8601f0bf 100644 --- a/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/ui/terminal/ProjectTabController.java +++ b/bundles/io.openliberty.tools.eclipse.ui/src/io/openliberty/tools/eclipse/ui/terminal/ProjectTabController.java @@ -245,6 +245,8 @@ public boolean isProjectTabMarkedClosed(String projectName) { if (tabTitle != null && tabTitle.startsWith("")) { return true; } + } else { + return true; } return false;