/* * Copyright 2000-2009 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.impl; import com.intellij.debugger.DebugEnvironment; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.DefaultDebugUIEnvironment; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.JavaDebugProcess; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.tree.render.BatchEvaluator; import com.intellij.execution.DefaultExecutionResult; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ExecutionEnvironmentBuilder; import com.intellij.execution.runners.JavaPatchableProgramRunner; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; 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.impl.XDebugSessionImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class GenericDebuggerRunner extends JavaPatchableProgramRunner { @Override public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) { return executorId.equals(DefaultDebugExecutor.EXECUTOR_ID) && profile instanceof ModuleRunProfile && !(profile instanceof RunConfigurationWithSuppressedDefaultDebugAction); } @Override @NotNull public String getRunnerId() { return DebuggingRunnerData.DEBUGGER_RUNNER_ID; } @Override protected RunContentDescriptor doExecute(@NotNull Project project, @NotNull RunProfileState state, @Nullable RunContentDescriptor contentToReuse, @NotNull ExecutionEnvironment env) throws ExecutionException { FileDocumentManager.getInstance().saveAllDocuments(); return createContentDescriptor(state, contentToReuse == null || env.getContentToReuse() == contentToReuse ? env : new ExecutionEnvironmentBuilder(env).contentToReuse(contentToReuse).build()); } @Nullable protected RunContentDescriptor createContentDescriptor(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { if (state instanceof JavaCommandLine) { final JavaParameters parameters = ((JavaCommandLine)state).getJavaParameters(); runCustomPatchers(parameters, environment.getExecutor(), environment.getRunProfile()); RemoteConnection connection = DebuggerManagerImpl.createDebugParameters(parameters, true, DebuggerSettings.getInstance().DEBUGGER_TRANSPORT, "", false); return attachVirtualMachine(state, environment, connection, true); } if (state instanceof PatchedRunnableState) { final RemoteConnection connection = doPatch(new JavaParameters(), environment.getRunnerSettings()); return attachVirtualMachine(state, environment, connection, true); } if (state instanceof RemoteState) { final RemoteConnection connection = createRemoteDebugConnection((RemoteState)state, environment.getRunnerSettings()); return attachVirtualMachine(state, environment, connection, false); } return null; } @Nullable protected RunContentDescriptor attachVirtualMachine(RunProfileState state, @NotNull ExecutionEnvironment env, RemoteConnection connection, boolean pollConnection) throws ExecutionException { DebugEnvironment environment = new DefaultDebugUIEnvironment(env, state, connection, pollConnection).getEnvironment(); final DebuggerSession debuggerSession = DebuggerManagerEx.getInstanceEx(env.getProject()).attachVirtualMachine(environment); if (debuggerSession == null) { return null; } final DebugProcessImpl debugProcess = debuggerSession.getProcess(); if (debugProcess.isDetached() || debugProcess.isDetaching()) { debuggerSession.dispose(); return null; } if (environment.isRemote()) { // optimization: that way BatchEvaluator will not try to lookup the class file in remote VM // which is an expensive operation when executed first time debugProcess.putUserData(BatchEvaluator.REMOTE_SESSION_KEY, Boolean.TRUE); } return XDebuggerManager.getInstance(env.getProject()).startSession(env, new XDebugProcessStarter() { @Override @NotNull public XDebugProcess start(@NotNull XDebugSession session) { XDebugSessionImpl sessionImpl = (XDebugSessionImpl)session; ExecutionResult executionResult = debugProcess.getExecutionResult(); sessionImpl.addExtraActions(executionResult.getActions()); if (executionResult instanceof DefaultExecutionResult) { sessionImpl.addRestartActions(((DefaultExecutionResult)executionResult).getRestartActions()); sessionImpl.addExtraStopActions(((DefaultExecutionResult)executionResult).getAdditionalStopActions()); } return new JavaDebugProcess(session, debuggerSession); } }).getRunContentDescriptor(); } private static RemoteConnection createRemoteDebugConnection(RemoteState connection, final RunnerSettings settings) { final RemoteConnection remoteConnection = connection.getRemoteConnection(); GenericDebuggerRunnerSettings debuggerRunnerSettings = (GenericDebuggerRunnerSettings)settings; if (debuggerRunnerSettings != null) { remoteConnection.setUseSockets(debuggerRunnerSettings.getTransport() == DebuggerSettings.SOCKET_TRANSPORT); remoteConnection.setAddress(debuggerRunnerSettings.DEBUG_PORT); } return remoteConnection; } @Override public GenericDebuggerRunnerSettings createConfigurationData(ConfigurationInfoProvider settingsProvider) { return new GenericDebuggerRunnerSettings(); } @Override public void patch(JavaParameters javaParameters, RunnerSettings settings, RunProfile runProfile, final boolean beforeExecution) throws ExecutionException { doPatch(javaParameters, settings); runCustomPatchers(javaParameters, Executor.EXECUTOR_EXTENSION_NAME.findExtension(DefaultDebugExecutor.class), runProfile); } private static RemoteConnection doPatch(final JavaParameters javaParameters, final RunnerSettings settings) throws ExecutionException { final GenericDebuggerRunnerSettings debuggerSettings = ((GenericDebuggerRunnerSettings)settings); if (StringUtil.isEmpty(debuggerSettings.getDebugPort())) { debuggerSettings.setDebugPort(DebuggerUtils.getInstance().findAvailableDebugAddress(debuggerSettings.getTransport() == DebuggerSettings.SOCKET_TRANSPORT)); } return DebuggerManagerImpl.createDebugParameters(javaParameters, debuggerSettings, false); } @Override public SettingsEditor getSettingsEditor(final Executor executor, RunConfiguration configuration) { if (configuration instanceof RunConfigurationWithRunnerSettings) { if (((RunConfigurationWithRunnerSettings)configuration).isSettingsNeeded()) { return new GenericDebuggerParametersRunnerConfigurable(configuration.getProject()); } } return null; } }