/* * Copyright (C) 2015 RoboVM AB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. */ package org.robovm.idea.running; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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.JavaDebugProcess; import com.intellij.debugger.impl.DebuggerSession; 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.configurations.RemoteConnection; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.GenericProgramRunner; import com.intellij.execution.runners.RunContentBuilder; import com.intellij.execution.ui.RunContentDescriptor; 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; public class RoboVmRunner extends GenericProgramRunner { public static final String DEBUG_EXECUTOR = "Debug"; public static final String RUN_EXECUTOR = "Run"; @NotNull @Override public String getRunnerId() { return "com.robovm.idea.running.RoboVmRunner"; } @Override public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { return (executorId.equals(DEBUG_EXECUTOR) || executorId.equals(RUN_EXECUTOR)) && profile instanceof RoboVmRunConfiguration; } @Override protected void execute(@NotNull ExecutionEnvironment environment, @Nullable Callback callback, @NotNull RunProfileState state) throws ExecutionException { // we need to pass the run profile info to the compiler so // we can decide if this is a debug or release build RoboVmRunConfiguration runConfig = (RoboVmRunConfiguration)environment.getRunnerAndConfigurationSettings().getConfiguration(); runConfig.setDebug(DEBUG_EXECUTOR.equals(environment.getExecutor().getId())); super.execute(environment, callback, state); } @Nullable @Override protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { if(DEBUG_EXECUTOR.equals(environment.getExecutor().getId())) { RoboVmRunConfiguration runConfig = (RoboVmRunConfiguration)environment.getRunProfile(); RemoteConnection connection = new RemoteConnection(true, "127.0.0.1", "" + runConfig.getDebugPort(), false); connection.setServerMode(true); return attachVirtualMachine(state, environment, connection, false); } else { ExecutionResult executionResult = state.execute(environment.getExecutor(), this); if (executionResult == null) { return null; } return new RunContentBuilder(executionResult, environment).showRunContent(environment.getContentToReuse()); } } @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; } // 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 JavaDebugProcess.create(session, debuggerSession); } }).getRunContentDescriptor(); } }