diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java new file mode 100644 index 000000000000..9c52a1389ff9 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaAttachDebuggerProvider.java @@ -0,0 +1,142 @@ +/* + * Copyright 2000-2016 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 com.intellij.debugger.engine; + +import com.intellij.debugger.DebugEnvironment; +import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.DefaultDebugEnvironment; +import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.RunManager; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.execution.configurations.RemoteConnection; +import com.intellij.execution.executors.DefaultDebugExecutor; +import com.intellij.execution.process.ProcessInfo; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ExecutionEnvironmentBuilder; +import com.intellij.internal.DebugAttachDetector; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.UserDataHolder; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.xdebugger.XDebugProcess; +import com.intellij.xdebugger.XDebugProcessStarter; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.attach.XDefaultLocalAttachGroup; +import com.intellij.xdebugger.attach.XLocalAttachDebugger; +import com.intellij.xdebugger.attach.XLocalAttachDebuggerProvider; +import com.intellij.xdebugger.attach.XLocalAttachGroup; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author egor + */ +public class JavaAttachDebuggerProvider implements XLocalAttachDebuggerProvider { + private static final XLocalAttachDebugger ourAttachDebugger = new XLocalAttachDebugger() { + @NotNull + @Override + public String getDebuggerDisplayName() { + return "Java Debugger"; + } + + @Override + public XDebugSession attachDebugSession(@NotNull Project project, @NotNull ProcessInfo processInfo) throws ExecutionException { + Pair address = getAttachAddress(processInfo); + assert address != null; + + // TODO: first need to remove circular dependency with execution-impl + //RunnerAndConfigurationSettings runSettings = RunManager.getInstance(project) + // .createRunConfiguration(StringUtil.notNullize(address.first) + ":" + address.second, + // RemoteConfigurationType.getInstance().getFactory()); + // + //RemoteConfiguration configuration = (RemoteConfiguration)runSettings.getConfiguration(); + //configuration.HOST = address.first; + //configuration.PORT = String.valueOf(address.second); + //configuration.USE_SOCKET_TRANSPORT = true; + //configuration.SERVER_MODE = false; + // + //ProgramRunnerUtil.executeConfiguration(project, runSettings, DefaultDebugExecutor.getDebugExecutorInstance()); + + String name = StringUtil.notNullize(address.first) + ":" + address.second; + RunnerAndConfigurationSettings runSettings = RunManager.getInstance(project) + .createRunConfiguration(name, ConfigurationTypeUtil.findConfigurationType("Remote").getConfigurationFactories()[0]); + + RemoteConnection remoteConnection = new RemoteConnection(true, address.first, String.valueOf(address.second), false); + ExecutionEnvironment env = new ExecutionEnvironmentBuilder(project, DefaultDebugExecutor.getDebugExecutorInstance()) + .runProfile(runSettings.getConfiguration()) + .build(); + DebugEnvironment environment = new DefaultDebugEnvironment(env, new RemoteStateState(project, remoteConnection), remoteConnection, 0); + final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(env.getProject()).attachVirtualMachine(environment); + if (debuggerSession == null) { + return null; + } + + return XDebuggerManager.getInstance(project).startSessionAndShowTab(name, null, new XDebugProcessStarter() { + @Override + @NotNull + public XDebugProcess start(@NotNull XDebugSession session) { + return JavaDebugProcess.create(session, debuggerSession); + } + }); + } + }; + + private static final XLocalAttachGroup ourAttachGroup = new XDefaultLocalAttachGroup() { + @Override + public int getOrder() { + return 1; + } + + @NotNull + @Override + public String getGroupName() { + return "Java"; + } + + @NotNull + @Override + public String getProcessDisplayText(@NotNull Project project, @NotNull ProcessInfo info) { + return info.getCommandLine(); + } + }; + + @NotNull + @Override + public XLocalAttachGroup getAttachGroup() { + return ourAttachGroup; + } + + @NotNull + @Override + public List getAvailableDebuggers(@NotNull Project project, + @NotNull ProcessInfo processInfo, + @NotNull UserDataHolder contextHolder) { + Pair address = getAttachAddress(processInfo); + if (address != null) { + return Collections.singletonList(ourAttachDebugger); + } + return Collections.emptyList(); + } + + private static Pair getAttachAddress(ProcessInfo processInfo) { + return DebugAttachDetector.getAttachAddress(StringUtil.split(processInfo.getCommandLine(), " ")); + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/DebugAttachDetector.java b/platform/platform-impl/src/com/intellij/internal/DebugAttachDetector.java index cc28a9cd01d5..04062074ee06 100644 --- a/platform/platform-impl/src/com/intellij/internal/DebugAttachDetector.java +++ b/platform/platform-impl/src/com/intellij/internal/DebugAttachDetector.java @@ -22,9 +22,11 @@ import com.intellij.notification.Notifications; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.util.net.NetUtils; import java.lang.management.ManagementFactory; +import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -40,14 +42,10 @@ public class DebugAttachDetector { private boolean myAttached; private boolean myReady; - public DebugAttachDetector() { - ApplicationEx app = ApplicationManagerEx.getApplicationEx(); - if (!app.isInternal() - || app.isUnitTestMode() - || app.isHeadlessEnvironment() - || "true".equals(System.getProperty("idea.debug.mode"))) return; - - for (String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) { + public static Pair getAttachAddress(List arguments) { + String host = null; + int port = -1; + for (String argument : arguments) { if (argument.startsWith("-agentlib:jdwp") && argument.contains("transport=dt_socket")) { String[] params = argument.split(","); for (String param : params) { @@ -55,16 +53,16 @@ public class DebugAttachDetector { try { String[] address = param.split("=")[1].split(":"); if (address.length == 1) { - myPort = Integer.parseInt(address[0]); + port = Integer.parseInt(address[0]); } else { - myHost = address[0]; - myPort = Integer.parseInt(address[1]); + host = address[0]; + port = Integer.parseInt(address[1]); } } catch (Exception e) { LOG.error(e); - return; + return null; } break; } @@ -72,8 +70,23 @@ public class DebugAttachDetector { break; } } + if (port > -1) { + return Pair.create(host, port); + } + return null; + } - if (myPort < 0) return; + public DebugAttachDetector() { + ApplicationEx app = ApplicationManagerEx.getApplicationEx(); + if (!app.isInternal() + || app.isUnitTestMode() + || app.isHeadlessEnvironment() + || "true".equals(System.getProperty("idea.debug.mode"))) return; + + Pair attachAddress = getAttachAddress(ManagementFactory.getRuntimeMXBean().getInputArguments()); + if (attachAddress == null) return; + myHost = attachAddress.first; + myPort = attachAddress.second; myTask = JobScheduler.getScheduler().scheduleWithFixedDelay(() -> { boolean attached = !NetUtils.canConnectToRemoteSocket(myHost, myPort); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index cba0ef581b1a..fb6a351caaf8 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1610,6 +1610,7 @@ +