Merge remote-tracking branch 'origin/master' into BETA_JAVA9
diff --git a/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
index b74a8b6..bea7112 100644
--- a/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
@@ -13,6 +13,7 @@
org.eclipse.jdt.debug.testplugin.launching,
org.eclipse.jdt.debug.tests,
org.eclipse.jdt.debug.tests.breakpoints,
+ org.eclipse.jdt.debug.tests.connectors,
org.eclipse.jdt.debug.tests.console,
org.eclipse.jdt.debug.tests.core,
org.eclipse.jdt.debug.tests.eval,
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index 4b4dd11..294d34d 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -41,6 +41,7 @@
import org.eclipse.jdt.debug.tests.breakpoints.TriggerPointBreakpointsTests;
import org.eclipse.jdt.debug.tests.breakpoints.TypeNameBreakpointTests;
import org.eclipse.jdt.debug.tests.breakpoints.WatchpointTests;
+import org.eclipse.jdt.debug.tests.connectors.MultipleConnectionsTest;
import org.eclipse.jdt.debug.tests.console.ConsoleTerminateAllActionTests;
import org.eclipse.jdt.debug.tests.console.IOConsoleTests;
import org.eclipse.jdt.debug.tests.console.JavaStackTraceConsoleTest;
@@ -304,6 +305,7 @@
// JDWP tests
addTest(new TestSuite(JDWPTests.class));
+ addTest(new TestSuite(MultipleConnectionsTest.class));
// Refresh state tests
addTest(new TestSuite(RefreshStateTests.class));
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MockLaunch.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MockLaunch.java
new file mode 100644
index 0000000..35e96d5
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MockLaunch.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.debug.tests.connectors;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.ISourceLocator;
+
+public class MockLaunch implements ILaunch {
+ private ConcurrentLinkedDeque<IProcess> processes = new ConcurrentLinkedDeque<>();
+ private ConcurrentLinkedDeque<IDebugTarget> targets = new ConcurrentLinkedDeque<>();
+ private ISourceLocator sourceLocator;
+ private Map<String, String> attributes = new HashMap<>();
+
+ @Override
+ public boolean canTerminate() {
+ for (IProcess p : processes) {
+ if (p.canTerminate()) {
+ return true;
+ }
+ }
+ for (IDebugTarget t : targets) {
+ if (t.canTerminate()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ for (IProcess p : processes) {
+ if (!p.isTerminated()) {
+ return false;
+ }
+ }
+ for (IDebugTarget t : targets) {
+ if (!t.isTerminated()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void terminate() throws DebugException {
+ for (Iterator<IProcess> iter = processes.iterator(); iter.hasNext(); iter.remove()) {
+ IProcess p = iter.next();
+ if (p.canTerminate()) {
+ p.terminate();
+ }
+ }
+ for (Iterator<IDebugTarget> iter = targets.iterator(); iter.hasNext(); iter.remove()) {
+ IDebugTarget t = iter.next();
+ if (t.canTerminate()) {
+ t.terminate();
+ }
+ }
+ }
+
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+ return null;
+ }
+
+ @Override
+ public Object[] getChildren() {
+ return new Object[0];
+ }
+
+ @Override
+ public IDebugTarget getDebugTarget() {
+ return null;
+ }
+
+ @Override
+ public IProcess[] getProcesses() {
+ return processes.toArray(new IProcess[processes.size()]);
+ }
+
+ @Override
+ public IDebugTarget[] getDebugTargets() {
+ return targets.toArray(new IDebugTarget[targets.size()]);
+ }
+
+ @Override
+ public void addDebugTarget(IDebugTarget target) {
+ targets.add(target);
+ }
+
+ @Override
+ public void removeDebugTarget(IDebugTarget target) {
+ targets.remove(target);
+ }
+
+ @Override
+ public void addProcess(IProcess process) {
+ processes.add(process);
+ }
+
+ @Override
+ public void removeProcess(IProcess process) {
+ processes.remove(process);
+ }
+
+ @Override
+ public ISourceLocator getSourceLocator() {
+ return sourceLocator;
+ }
+
+ @Override
+ public void setSourceLocator(ISourceLocator locator) {
+ sourceLocator = locator;
+ }
+
+ @Override
+ public String getLaunchMode() {
+ return ILaunchManager.RUN_MODE;
+ }
+
+ @Override
+ public ILaunchConfiguration getLaunchConfiguration() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String key, String value) {
+ attributes.put(key, value);
+ }
+
+ @Override
+ public String getAttribute(String key) {
+ return attributes.get(key);
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return getChildren().length > 0;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MultipleConnectionsTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MultipleConnectionsTest.java
new file mode 100644
index 0000000..caf70b7
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/connectors/MultipleConnectionsTest.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.debug.tests.connectors;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.internal.launching.SocketListenConnector;
+import org.eclipse.jdt.launching.SocketUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sun.jdi.connect.Connector;
+
+/**
+ * Test the SocketListenerConnector
+ */
+public class MultipleConnectionsTest extends AbstractDebugTest {
+
+ public MultipleConnectionsTest(String name) {
+ super(name);
+ }
+
+ private ILaunch launch = new MockLaunch();
+
+ private SocketListenConnector connector;
+
+ private int port;
+
+ @Override
+ @Before
+ protected void setUp() throws Exception {
+ super.setUp();
+ port = SocketUtil.findFreePort();
+ }
+
+ @Test
+ public void testDefaultSettings() throws CoreException {
+ connector = new SocketListenConnector();
+ Map<String, Connector.Argument> defaults = connector.getDefaultArguments();
+ assertTrue(defaults.containsKey("connectionLimit"));
+ assertEquals(1, ((Connector.IntegerArgument) defaults.get("connectionLimit")).intValue());
+ }
+
+ /**
+ * Ensure out-of-the-box settings mimics previous behaviour of accepting a
+ * single connection
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testDefaultBehaviour() throws CoreException, InterruptedException {
+ connector = new SocketListenConnector();
+ Map<String, String> arguments = new HashMap<>();
+ arguments.put("port", Integer.toString(port));
+ connector.connect(arguments, new NullProgressMonitor(), launch);
+ Thread.sleep(200);
+
+ assertTrue("first connect should succeed", connect());
+ assertFalse("second connect should fail", connect());
+ }
+
+ /**
+ * Ensure connector accepts a single connection
+ *
+ * @throws InterruptedException
+ */
+ @Test
+ public void testSingleConnectionBehaviour() throws CoreException, InterruptedException {
+ connector = new SocketListenConnector();
+ Map<String, String> arguments = new HashMap<>();
+ arguments.put("port", Integer.toString(port));
+ arguments.put("connectionLimit", "1");
+ connector.connect(arguments, new NullProgressMonitor(), launch);
+ Thread.sleep(200);
+
+ assertTrue("first connect should succeed", connect());
+ assertFalse("second connect should fail", connect());
+ }
+
+ /**
+ * Ensure out-of-the-box settings mimics previous behaviour of accepting a
+ * single connection
+ *
+ * @throws InterruptedException
+ */
+ @Test
+ public void testTwoConnectionsBehaviour() throws CoreException, InterruptedException {
+ connector = new SocketListenConnector();
+ Map<String, String> arguments = new HashMap<>();
+ arguments.put("port", Integer.toString(port));
+ arguments.put("connectionLimit", "2");
+ connector.connect(arguments, new NullProgressMonitor(), launch);
+ Thread.sleep(200);
+
+ assertTrue("first connect should succeed", connect());
+ assertTrue("second connect should succeed", connect());
+ }
+
+ /**
+ * Ensure out-of-the-box settings mimics previous behaviour of accepting a
+ * single connection
+ *
+ * @throws InterruptedException
+ */
+ @Test
+ public void testUnlimitedConnectionsBehaviour() throws CoreException, InterruptedException {
+ connector = new SocketListenConnector();
+ Map<String, String> arguments = new HashMap<>();
+ arguments.put("port", Integer.toString(port));
+ arguments.put("connectionLimit", "0");
+ connector.connect(arguments, new NullProgressMonitor(), launch);
+ Thread.sleep(200);
+
+ for (int i = 0; i < 10; i++) {
+ assertTrue("connection " + i + " should succeed", connect());
+ }
+ }
+
+ @Override
+ @After
+ protected void tearDown() throws Exception {
+ launch.terminate();
+ super.tearDown();
+ }
+
+ private boolean connect() {
+ boolean result = true;
+ // Two try blocks to distinguish between exceptions from socket close (ignorable)
+ // and from dealing with the remote (errors)
+ try (Socket s = new Socket()) {
+ try {
+ s.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));
+ byte[] buffer = new byte[14];
+ s.getInputStream().read(buffer);
+ assertEquals("JDWP-Handshake", new String(buffer));
+ s.getOutputStream().write("JDWP-Handshake".getBytes());
+ s.getOutputStream().flush();
+ // Closing gracelessly like this produces
+ // com.sun.jdi.VMDisconnectedExceptions on the log. Could
+ // respond to JDWP to try to bring down the connections
+ // gracefully, but it's a bit involved.
+ } catch (IOException e) {
+ result = false;
+ }
+ } catch(IOException e) {
+ }
+ try {
+ // sleep to allow the remote side to setup the connection
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
index a9b44b0..0e90a66 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
@@ -49,6 +49,7 @@
public static String JavaDebugPreferencePage_27;
public static String JavaDebugPreferencePage_description;
+ public static String JavaDebugPreferencePage_Enable_hot_code_replace_1;
public static String JavaDebugPreferencePage_Alert_me_when_hot_code_replace_fails_1;
public static String JavaDebugPreferencePage_Alert_me_when_hot_code_replace_is_not_supported_1;
public static String JavaDebugPreferencePage_Alert_me_when_obsolete_methods_remain_1;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
index ac30067..4b0bf61 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
@@ -17,6 +17,7 @@
ImageDescriptorRegistry_Allocating_image_for_wrong_display_1=Allocating image for wrong display
JavaDebugPreferencePage_description=General settings for Java Debugging.
+JavaDebugPreferencePage_Enable_hot_code_replace_1=Enable hot code replace
JavaDebugPreferencePage_Alert_me_when_hot_code_replace_fails_1=Show error when hot code replace &fails
JavaDebugPreferencePage_Alert_me_when_hot_code_replace_is_not_supported_1=Show error when hot code replace is not &supported
JavaDebugPreferencePage_Alert_me_when_obsolete_methods_remain_1=Show error when &obsolete methods remain after hot code replace
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
index c1d21b7..bb02b14 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
@@ -1048,7 +1048,7 @@
}
if (breakpoint.isTriggerPoint()) {
flags |= JDIImageDescriptor.TRIGGER_POINT;
- } else if (!DebugPlugin.getDefault().getBreakpointManager().canSupendOnBreakpoint()) {
+ } else if (DebugPlugin.getDefault().getBreakpointManager().hasActiveTriggerPoints()) {
flags |= JDIImageDescriptor.TRIGGER_SUPPRESSED;
}
if (breakpoint instanceof IJavaLineBreakpoint) {
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
index 423452f..2cf30b8 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
@@ -85,6 +85,7 @@
private Combo fWatchpoint;
// Hot code replace preference widgets
+ private Button fEnableHCRButton;
private Button fAlertHCRButton;
private Button fAlertHCRNotSupportedButton;
private Button fAlertObsoleteButton;
@@ -138,6 +139,7 @@
fWatchpoint.setFont(group.getFont());
group = SWTFactory.createGroup(composite, DebugUIMessages.JavaDebugPreferencePage_Hot_Code_Replace_2, 1, 1, GridData.FILL_HORIZONTAL);
+ fEnableHCRButton = SWTFactory.createCheckButton(group, DebugUIMessages.JavaDebugPreferencePage_Enable_hot_code_replace_1, null, true, 1);
fAlertHCRButton = SWTFactory.createCheckButton(group, DebugUIMessages.JavaDebugPreferencePage_Alert_me_when_hot_code_replace_fails_1, null, false, 1);
fAlertHCRNotSupportedButton = SWTFactory.createCheckButton(group, DebugUIMessages.JavaDebugPreferencePage_Alert_me_when_hot_code_replace_is_not_supported_1, null, false, 1);
fAlertObsoleteButton = SWTFactory.createCheckButton(group, DebugUIMessages.JavaDebugPreferencePage_Alert_me_when_obsolete_methods_remain_1, null, false, 1);
@@ -199,6 +201,7 @@
store.setValue(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION, fOpenInspector.getSelection());
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
if(prefs != null) {
+ prefs.putBoolean(JDIDebugPlugin.PREF_ENABLE_HCR, fEnableHCRButton.getSelection());
prefs.putBoolean(JDIDebugModel.PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION, fSuspendDuringEvaluations.getSelection());
int selectionIndex = fSuspendVMorThread.getSelectionIndex();
int policy = IJavaBreakpoint.SUSPEND_THREAD;
@@ -248,6 +251,7 @@
fOpenInspector.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION));
IEclipsePreferences prefs = DefaultScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
if(prefs != null) {
+ fEnableHCRButton.setSelection(prefs.getBoolean(JDIDebugPlugin.PREF_ENABLE_HCR, true));
fSuspendDuringEvaluations.setSelection(prefs.getBoolean(JDIDebugModel.PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION, true));
int value = prefs.getInt(JDIDebugPlugin.PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY, IJavaBreakpoint.SUSPEND_THREAD);
fSuspendVMorThread.select((value == IJavaBreakpoint.SUSPEND_THREAD) ? 0 : 1);
@@ -281,6 +285,7 @@
fOpenInspector.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION));
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
if(prefs != null) {
+ fEnableHCRButton.setSelection(prefs.getBoolean(JDIDebugPlugin.PREF_ENABLE_HCR, true));
fSuspendDuringEvaluations.setSelection(prefs.getBoolean(JDIDebugModel.PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION, true));
int value = prefs.getInt(JDIDebugPlugin.PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY, IJavaBreakpoint.SUSPEND_THREAD);
fSuspendVMorThread.select((value == IJavaBreakpoint.SUSPEND_THREAD ? 0 : 1));
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java
index aa1b36e..d8307c0 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java
@@ -1,12 +1,13 @@
/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * IBM - Initial API and implementation
+ * IBM - Initial API and implementation
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdi.internal.connect;
@@ -52,6 +53,10 @@
public static String SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6;
public static String SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7;
public static String SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8;
+ public static String SocketListeningConnectorImpl_Limit;
+
+ public static String SocketListeningConnectorImpl_Limit_incoming_connections;
+
public static String SocketListeningConnectorImpl_ListeningConnector_Socket_Port;
public static String SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1;
public static String SocketRawLaunchingConnectorImpl_Command_2;
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
index 01c6a55..a10c8bd 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2008 IBM Corporation and others.
+# Copyright (c) 2000, 2016 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
#
# Contributors:
# IBM Corporation - initial API and implementation
+# Google Inc - add support for accepting multiple connections
###############################################################################
PacketReceiveManager_Got_IOException_from_Virtual_Machine_1=Got IOException from Virtual Machine
@@ -46,6 +47,8 @@
SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6=Connection argument is not of the right type
SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7=Necessary connection argument is null
SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8=Connection argument is not a number
+SocketListeningConnectorImpl_Limit=Connection limit:
+SocketListeningConnectorImpl_Limit_incoming_connections=Limit incoming connections (0 = no limit)
SocketListeningConnectorImpl_ListeningConnector_Socket_Port=ListeningConnector Socket Port=
SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1=Raw command to start the debugged application VM
SocketRawLaunchingConnectorImpl_Command_2=Command:
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java
index 036be8c..858fcc1 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,22 +7,32 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdi.internal.connect;
import java.io.DataInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.net.Socket;
import com.sun.jdi.connect.spi.ClosedConnectionException;
import com.sun.jdi.connect.spi.Connection;
public class SocketConnection extends Connection {
- private SocketTransportService fTransport;
+ // for attaching connector
+ private Socket fSocket;
- SocketConnection(SocketTransportService transport) {
- fTransport = transport;
+ private InputStream fInput;
+
+ private OutputStream fOutput;
+
+ SocketConnection(Socket socket, InputStream in, OutputStream out) {
+ fSocket = socket;
+ fInput = in;
+ fOutput = out;
}
/*
@@ -32,11 +42,11 @@
*/
@Override
public synchronized void close() throws IOException {
- if (fTransport == null)
+ if (fSocket == null)
return;
- fTransport.close();
- fTransport = null;
+ fSocket.close();
+ fSocket = null;
}
/*
@@ -46,7 +56,7 @@
*/
@Override
public synchronized boolean isOpen() {
- return fTransport != null;
+ return fSocket != null;
}
/*
@@ -61,7 +71,7 @@
if (!isOpen()) {
throw new ClosedConnectionException();
}
- stream = new DataInputStream(fTransport.getInputStream());
+ stream = new DataInputStream(fInput);
}
synchronized (stream) {
int packetLength = 0;
@@ -121,7 +131,7 @@
if (!isOpen()) {
throw new ClosedConnectionException();
}
- stream = fTransport.getOutputStream();
+ stream = fOutput;
}
synchronized (stream) {
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java
index 92c141c..ce62aa4 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately
* from Eclipse
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdi.internal.connect;
@@ -58,6 +59,12 @@
"timeout", ConnectMessages.SocketListeningConnectorImpl_Timeout_before_accept_returns_3, ConnectMessages.SocketListeningConnectorImpl_Timeout_4, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$
arguments.put(intArg.name(), intArg);
+ // FIXME: connectionLimit is not actually used in this class, but in the higher-level controller, SocketListenConnector.
+ // But IntegerArgumentImpl is package restricted so we must put it here.
+ intArg = new IntegerArgumentImpl("connectionLimit", ConnectMessages.SocketListeningConnectorImpl_Limit_incoming_connections, ConnectMessages.SocketListeningConnectorImpl_Limit, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$
+ intArg.setValue(1); // mimics previous behaviour, allowing a single connection
+ arguments.put(intArg.name(), intArg);
+
return arguments;
}
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
index b0c62a8..e8b2c75 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately
* from Eclipse
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdi.internal.connect;
@@ -73,13 +74,6 @@
}
}
- // for attaching connector
- private Socket fSocket;
-
- private InputStream fInput;
-
- private OutputStream fOutput;
-
// for listening or accepting connectors
private ServerSocket fServerSocket;
@@ -99,15 +93,16 @@
}
fServerSocket.setSoTimeout((int) attachTimeout);
}
+ Socket socket;
try {
- fSocket = fServerSocket.accept();
+ socket = fServerSocket.accept();
} catch (SocketTimeoutException e) {
throw new TransportTimeoutException();
}
- fInput = fSocket.getInputStream();
- fOutput = fSocket.getOutputStream();
- performHandshake(fInput, fOutput, handshakeTimeout);
- return new SocketConnection(this);
+ InputStream input = socket.getInputStream();
+ OutputStream output = socket.getOutputStream();
+ performHandshake(input, output, handshakeTimeout);
+ return new SocketConnection(socket, input, output);
}
/*
@@ -141,14 +136,16 @@
}
final IOException[] ex = new IOException[1];
+ final SocketConnection[] result = new SocketConnection[1];
Thread attachThread = new Thread(new Runnable() {
@Override
public void run() {
try {
- fSocket = new Socket(host, port);
- fInput = fSocket.getInputStream();
- fOutput = fSocket.getOutputStream();
- performHandshake(fInput, fOutput, handshakeTimeout);
+ Socket socket = new Socket(host, port);
+ InputStream input = socket.getInputStream();
+ OutputStream output = socket.getOutputStream();
+ performHandshake(input, output, handshakeTimeout);
+ result[0] = new SocketConnection(socket, input, output);
} catch (IOException e) {
ex[0] = e;
}
@@ -169,7 +166,7 @@
throw ex[0];
}
- return new SocketConnection(this);
+ return result[0];
}
void performHandshake(final InputStream in, final OutputStream out,
@@ -316,34 +313,4 @@
}
fServerSocket = null;
}
-
- /**
- * Closes the current open socket, the transport service will continue to
- * listen for new incoming connections.
- */
- public void close() {
- if (fSocket != null) {
- try {
- fSocket.close();
- } catch (IOException e) {
- }
- }
- fSocket = null;
- fInput = null;
- fOutput = null;
- }
-
- /**
- * @return current socket input stream or <code>null</code>
- */
- public InputStream getInputStream() {
- return fInput;
- }
-
- /**
- * @return curernt socket output stream or <code>null</code>
- */
- public OutputStream getOutputStream() {
- return fOutput;
- }
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java
index 1fec036..4988e17 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ITriggerPoint;
/**
* A breakpoint specific to the Java debug model. A Java breakpoint supports:
@@ -29,7 +30,7 @@
* @noimplement This interface is not intended to be implemented by clients.
* @noextend This interface is not intended to be extended by clients.
*/
-public interface IJavaBreakpoint extends IBreakpoint {
+public interface IJavaBreakpoint extends IBreakpoint, ITriggerPoint {
/**
* Suspend policy constant indicating a breakpoint will suspend the target
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java
index 8ff5d0b..64520fa 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java
@@ -55,6 +55,14 @@
public class JDIDebugPlugin extends Plugin implements IEclipsePreferences.IPreferenceChangeListener {
/**
+ * Boolean preference controlling if hot code replace is enabled.
+ *
+ * @since 3.11
+ */
+ public static final String PREF_ENABLE_HCR = JDIDebugPlugin
+ .getUniqueIdentifier() + ".enable_hcr"; //$NON-NLS-1$
+
+ /**
* integer preference controlling if we should, by default, suspend the VM
* instead of the thread
*
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
index a7062c6..080b144 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
@@ -32,6 +32,7 @@
@Override
public void initializeDefaultPreferences() {
IEclipsePreferences node = DefaultScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
+ node.putBoolean(JDIDebugPlugin.PREF_ENABLE_HCR, true);
node.putInt(JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT);
node.putBoolean(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, true);
node.putBoolean(JDIDebugModel.PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION, true);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java
index 585417e..c8cff8f 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java
@@ -480,7 +480,7 @@
protected void disableTriggerPoint(Event event) {
try{
if (isTriggerPoint() && isEnabled()) {
- DebugPlugin.getDefault().getBreakpointManager().enableTriggerpoints(null, false);
+ DebugPlugin.getDefault().getBreakpointManager().enableTriggerPoints(null, false);
// make a note that we auto-disabled the trigger point for this breakpoint.
// we re enable it at cleanup of JDITarget
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
index 0b9e4e2..27facfb 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
@@ -444,6 +444,16 @@
*/
private void doHotCodeReplace(List<JDIDebugTarget> targets, List<IResource> resources,
List<String> qualifiedNames) {
+
+ // Check whether hot code replace is enabled
+ if (!Platform.getPreferencesService().getBoolean(
+ JDIDebugPlugin.getUniqueIdentifier(),
+ JDIDebugPlugin.PREF_ENABLE_HCR,
+ true,
+ null)) {
+ return; // disabled
+ }
+
MultiStatus ms = new MultiStatus(
JDIDebugPlugin.getUniqueIdentifier(),
DebugException.TARGET_REQUEST_FAILED,
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
index 9d930d4..24288c8 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
@@ -1863,7 +1863,7 @@
plugin.getBreakpointManager().removeBreakpointManagerListener(this);
plugin.removeDebugEventListener(this);
removeAllBreakpoints();
- DebugPlugin.getDefault().getBreakpointManager().enableTriggerpoints(null, true);
+ DebugPlugin.getDefault().getBreakpointManager().enableTriggerPoints(null, true);
fOutOfSynchTypes.clear();
if (fEngines != null) {
Iterator<IAstEvaluationEngine> engines = fEngines.values().iterator();
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
index 8797935..a9231e9 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
@@ -1430,7 +1430,7 @@
try {
if (!(breakpoint.isTriggerPoint())) {
- if (!DebugPlugin.getDefault().getBreakpointManager().canSupendOnBreakpoint()){
+ if (DebugPlugin.getDefault().getBreakpointManager().hasActiveTriggerPoints()){
fSuspendVoteInProgress = false;
return false;
}
@@ -1772,7 +1772,7 @@
return;
}
}
- StepHandler handler = new StepIntoHandler();
+ StepHandler handler = createStepIntoHandler();
handler.step();
}
@@ -1789,7 +1789,7 @@
return;
}
}
- StepHandler handler = new StepOverHandler();
+ StepHandler handler = createStepOverHandler();
handler.step();
}
@@ -1806,7 +1806,7 @@
return;
}
}
- StepHandler handler = new StepReturnHandler();
+ StepHandler handler = createStepReturnHandler();
handler.step();
}
@@ -2135,7 +2135,7 @@
// This block is synchronized, such that the step request
// begins before a background evaluation can be performed.
synchronized (this) {
- StepHandler handler = new DropToFrameHandler(frame);
+ StepHandler handler = createDropToFrameHandler(frame);
handler.step();
}
}
@@ -2204,7 +2204,7 @@
return;
}
}
- StepHandler handler = new StepToFrameHandler(frame);
+ StepHandler handler = createStepToFrameHandler(frame);
handler.step();
}
@@ -3045,7 +3045,7 @@
/**
* Handler for step into requests.
*/
- class StepIntoHandler extends StepHandler {
+ protected class StepIntoHandler extends StepHandler {
/*
* (non-Javadoc)
@@ -3074,7 +3074,7 @@
/**
* Handler for step return requests.
*/
- class StepReturnHandler extends StepHandler {
+ protected class StepReturnHandler extends StepHandler {
/*
* (non-Javadoc)
*
@@ -3120,7 +3120,7 @@
* stack frame). Step returns are performed until a specified stack frame is
* reached or the thread is suspended (explicitly, or by a breakpoint).
*/
- class StepToFrameHandler extends StepReturnHandler {
+ protected class StepToFrameHandler extends StepReturnHandler {
/**
* The number of frames that should be left on the stack
@@ -3202,7 +3202,7 @@
/**
* Handles dropping to a specified frame.
*/
- class DropToFrameHandler extends StepReturnHandler {
+ protected class DropToFrameHandler extends StepReturnHandler {
/**
* The number of frames to drop off the stack.
@@ -3714,5 +3714,25 @@
return (IJavaObject) JDIValue
.createValue(getJavaDebugTarget(), fThread);
}
+
+ protected StepIntoHandler createStepIntoHandler() {
+ return new StepIntoHandler();
+ }
+ protected StepOverHandler createStepOverHandler() {
+ return new StepOverHandler();
+ }
+
+ protected StepReturnHandler createStepReturnHandler() {
+ return new StepReturnHandler();
+ }
+
+ protected StepToFrameHandler createStepToFrameHandler(IStackFrame stackFrame) throws DebugException {
+ return new StepToFrameHandler(stackFrame);
+ }
+
+ protected DropToFrameHandler createDropToFrameHandler(IStackFrame stackFrame) throws DebugException {
+ return new DropToFrameHandler(stackFrame);
+ }
+
}
\ No newline at end of file
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnector.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnector.java
index 8ce56d7..7ee5de3 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnector.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2015 IBM Corporation and others.
+ * Copyright (c) 2007, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdt.internal.launching;
@@ -100,11 +101,16 @@
Connector.Argument param= acceptArguments.get("port"); //$NON-NLS-1$
param.setValue(portNumberString);
+ // retain default behaviour to accept 1 connection only
+ int connectionLimit = 1;
+ if (arguments.containsKey("connectionLimit")) { //$NON-NLS-1$
+ connectionLimit = Integer.valueOf(arguments.get("connectionLimit")); //$NON-NLS-1$
+ }
+
try {
monitor.subTask(NLS.bind(LaunchingMessages.SocketListenConnector_3, new String[]{portNumberString}));
connector.startListening(acceptArguments);
- SocketListenConnectorProcess process = new SocketListenConnectorProcess(launch,portNumberString);
- launch.addProcess(process);
+ SocketListenConnectorProcess process = new SocketListenConnectorProcess(launch, portNumberString, connectionLimit);
process.waitForConnection(connector, acceptArguments);
} catch (IOException e) {
abort(LaunchingMessages.SocketListenConnector_4, e, IJavaLaunchConfigurationConstants.ERR_REMOTE_VM_CONNECTION_FAILED);
@@ -119,8 +125,10 @@
@Override
public Map<String, Connector.Argument> getDefaultArguments() throws CoreException {
Map<String, Connector.Argument> def = getListeningConnector().defaultArguments();
+
Connector.IntegerArgument arg = (Connector.IntegerArgument)def.get("port"); //$NON-NLS-1$
arg.setValue(8000);
+
return def;
}
@@ -131,6 +139,7 @@
public List<String> getArgumentOrder() {
List<String> list = new ArrayList<String>(1);
list.add("port"); //$NON-NLS-1$
+ list.add("connectionLimit"); //$NON-NLS-1$
return list;
}
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnectorProcess.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnectorProcess.java
index c7587c5..15f8c7f 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnectorProcess.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/SocketListenConnectorProcess.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2015 IBM Corporation and others.
+ * Copyright (c) 2007, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,10 +7,13 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdt.internal.launching;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
@@ -41,16 +44,14 @@
import com.sun.jdi.connect.TransportTimeoutException;
/**
- * A process that represents a VM listening connector that is waiting
- * for a VM to remotely connect. Allows the user to see the status
- * of the connection and terminate it. If a successful connection
- * occurs, the debug target is added to the launch and this process
- * is removed.
+ * A process that represents a VM listening connector that is waiting for some VM(s) to remotely connect. Allows the user to see the status of the
+ * connection and terminate it. If a successful connection occurs, the debug target is added to the launch and, if a configured number of connections
+ * have been reached, then this process is removed.
+ *
* @since 3.4
* @see SocketListenConnector
*/
public class SocketListenConnectorProcess implements IProcess {
-
/**
* Whether this process has been terminated.
*/
@@ -64,19 +65,30 @@
*/
private String fPort;
/**
+ * The number of incoming connections to accept (0 = unlimited). Setting to 1 mimics previous behaviour.
+ */
+ private int fConnectionLimit;
+ /** The number of connections accepted so far. */
+ private int fAccepted = 0;
+ /**
* The system job that will wait for incoming VM connections.
*/
private WaitForConnectionJob fWaitForConnectionJob;
+ /** Time when this instance was created (milliseconds) */
+ private long fStartTime;
+
/**
* Creates this process. The label for this process will state
* the port the connector is listening at.
* @param launch the launch this process belongs to
* @param port the port the connector will wait on
+ * @param connectionLimit the number of incoming connections to accept (0 = unlimited)
*/
- public SocketListenConnectorProcess(ILaunch launch, String port){
+ public SocketListenConnectorProcess(ILaunch launch, String port, int connectionLimit){
fLaunch = launch;
fPort = port;
+ fConnectionLimit = connectionLimit;
}
/**
@@ -95,8 +107,21 @@
if (isTerminated()){
throw new CoreException(getStatus(LaunchingMessages.SocketListenConnectorProcess_0, null, IJavaLaunchConfigurationConstants.ERR_REMOTE_VM_CONNECTION_FAILED));
}
- fWaitForConnectionJob = new WaitForConnectionJob(this,connector,arguments);
+ fStartTime = System.currentTimeMillis();
+ fAccepted = 0;
+ // If the connector does not support multiple connections, accept a single connection
+ try {
+ if (!connector.supportsMultipleConnections()) {
+ fConnectionLimit = 1;
+ }
+ }
+ catch (IOException | IllegalConnectorArgumentsException ex) {
+ fConnectionLimit = 1;
+ }
+ fLaunch.addProcess(this);
+ fWaitForConnectionJob = new WaitForConnectionJob(connector,arguments);
fWaitForConnectionJob.setPriority(Job.SHORT);
+ fWaitForConnectionJob.setSystem(true);
fWaitForConnectionJob.addJobChangeListener(new JobChangeAdapter(){
@Override
public void running(IJobChangeEvent event) {
@@ -104,7 +129,9 @@
}
@Override
public void done(IJobChangeEvent event) {
- if (event.getResult().equals(Status.CANCEL_STATUS)){
+ if (event.getResult().isOK() && continueListening()) {
+ fWaitForConnectionJob.schedule();
+ } else {
try{
terminate();
} catch (DebugException e){}
@@ -115,6 +142,13 @@
}
/**
+ * Return true if this connector should continue listening for further connections.
+ */
+ protected boolean continueListening() {
+ return !isTerminated() && (fConnectionLimit <= 0 || fConnectionLimit - fAccepted > 0);
+ }
+
+ /**
* Returns an error status using the passed parameters.
*
* @param message the status message
@@ -174,6 +208,7 @@
public void terminate() throws DebugException {
if (!fTerminated){
fTerminated = true;
+ fLaunch.removeProcess(this);
if (fWaitForConnectionJob != null){
fWaitForConnectionJob.cancel();
fWaitForConnectionJob.stopListening();
@@ -236,13 +271,24 @@
}
/**
- * Job that waits for incoming VM connections. When a remote
- * VM connection is accepted, a debug target is created and
- * the process that created this job is removed.
+ * Return the time since this connector was started.
+ */
+ private String getRunningTime() {
+ long total = System.currentTimeMillis() - fStartTime;
+ StringWriter result = new StringWriter();
+ PrintWriter writer = new PrintWriter(result);
+ int minutes = (int) (total / 60 / 1000);
+ int seconds = (int) (total / 1000) % 60;
+ int milliseconds = (int) (total / 1000) % 1000;
+ writer.printf("%02d:%02d.%03d", minutes, seconds, milliseconds).close(); //$NON-NLS-1$
+ return result.toString();
+ }
+
+ /**
+ * Job that waits for incoming VM connections. When a remote VM connection is accepted, a debug target is created.
*/
class WaitForConnectionJob extends Job{
- private IProcess fWaitProcess;
private ListeningConnector fConnector;
private Map<String, Connector.Argument> fArguments;
/**
@@ -253,9 +299,8 @@
*/
private boolean fListeningStopped = false;
- public WaitForConnectionJob(IProcess waitProcess, ListeningConnector connector, Map<String, Connector.Argument> arguments) {
+ public WaitForConnectionJob(ListeningConnector connector, Map<String, Connector.Argument> arguments) {
super(getLabel());
- fWaitProcess = waitProcess;
fConnector = connector;
fArguments = arguments;
}
@@ -297,7 +342,7 @@
String vmLabel = constructVMLabel(vm, portArg.value(), fLaunch.getLaunchConfiguration());
IDebugTarget debugTarget= JDIDebugModel.newDebugTarget(fLaunch, vm, vmLabel, null, allowTerminate, true);
fLaunch.addDebugTarget(debugTarget);
- fLaunch.removeProcess(fWaitProcess);
+ fAccepted++;
return Status.OK_STATUS;
} catch (IOException e) {
if (fListeningStopped){
@@ -306,9 +351,6 @@
return getStatus(LaunchingMessages.SocketListenConnectorProcess_4, e, IJavaLaunchConfigurationConstants.ERR_REMOTE_VM_CONNECTION_FAILED);
} catch (IllegalConnectorArgumentsException e) {
return getStatus(LaunchingMessages.SocketListenConnectorProcess_4, e, IJavaLaunchConfigurationConstants.ERR_REMOTE_VM_CONNECTION_FAILED);
- } finally {
- // Always try to close the socket
- stopListening();
}
}
@@ -363,6 +405,11 @@
}
}
StringBuffer buffer = new StringBuffer(name);
+ if (fConnectionLimit != 1) {
+ // if we're accepting multiple incoming connections,
+ // append the time when each connection was accepted
+ buffer.append('<').append(getRunningTime()).append('>');
+ }
buffer.append('[');
buffer.append(port);
buffer.append(']');
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractVMInstallType.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractVMInstallType.java
index 3d91a2b..d475501 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractVMInstallType.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/AbstractVMInstallType.java
@@ -15,6 +15,7 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
@@ -42,7 +43,7 @@
* Constructs a new VM install type.
*/
protected AbstractVMInstallType() {
- fVMs= new ArrayList<IVMInstall>(10);
+ fVMs = new ArrayList<>(10);
}
/* (non-Javadoc)
@@ -61,16 +62,18 @@
*/
@Override
public void disposeVMInstall(String id) {
+ IVMInstall removedVM = null;
synchronized (this) {
for (int i= 0; i < fVMs.size(); i++) {
- IVMInstall vm= fVMs.get(i);
- if (vm.getId().equals(id)) {
- fVMs.remove(i);
- JavaRuntime.fireVMRemoved(vm);
- return;
+ if (fVMs.get(i).getId().equals(id)) {
+ removedVM = fVMs.remove(i);
+ break;
}
}
}
+ if (removedVM != null) {
+ JavaRuntime.fireVMRemoved(removedVM);
+ }
}
/* (non-Javadoc)
@@ -155,7 +158,7 @@
synchronized (this) {
for (int i = 0; i < fVMs.size(); i++) {
IVMInstall vm = fVMs.get(i);
- if (vm.getName().equals(name)) {
+ if (Objects.equals(vm.getName(), name)) {
return vm;
}
}