com.google.cloud.tools.intellij.debugger.CloudDebuggerRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.google.cloud.tools.intellij.debugger.CloudDebuggerRunner.java

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.google.cloud.tools.intellij.debugger;

import com.google.api.client.util.Lists;
import com.google.cloud.tools.intellij.debugger.ui.CloudAttachDialog;
import com.google.cloud.tools.intellij.ui.GoogleCloudToolsIcons;
import com.google.cloud.tools.intellij.util.GctBundle;

import com.intellij.execution.ExecutionException;
import com.intellij.execution.RunCanceledByUserException;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.runners.DefaultProgramRunner;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.execution.ui.layout.impl.RunnerContentUi;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;

import git4idea.DialogManager;

import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

/**
 * The CloudDebuggerRunner shows the attach dialog, creates a cloud process representation and
 * returns a content descriptor once logically "attached".
 */
public class CloudDebuggerRunner extends DefaultProgramRunner {

    private static final String EXECUTOR_TARGET = "Debug";
    @NonNls
    private static final String ID = "CloudDebuggerRunner";

    @Override
    public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
        return profile instanceof CloudDebugRunConfiguration && EXECUTOR_TARGET.equals(executorId);
    }

    @Override
    protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment env)
            throws ExecutionException {

        ensureSingleDebugSession(env.getProject());

        CloudDebugProcessState cloudState = null;
        if (state instanceof CloudDebugProcessState) {
            cloudState = (CloudDebugProcessState) state;
        }
        FileDocumentManager.getInstance().saveAllDocuments();
        state.execute(env.getExecutor(), this);

        return createContentDescriptor(cloudState, env);
    }

    @NotNull
    @Override
    public String getRunnerId() {
        return ID;
    }

    private static RunContentDescriptor createContentDescriptor(@Nullable final CloudDebugProcessState processState,
            @NotNull final ExecutionEnvironment environment) throws ExecutionException {

        final XDebugSession debugSession = XDebuggerManager.getInstance(environment.getProject())
                .startSession(environment, new XDebugProcessStarter() {
                    @NotNull
                    @Override
                    public XDebugProcess start(@NotNull final XDebugSession session) throws ExecutionException {

                        // Clear out the stash state which is queried on debug exit.
                        if (processState != null) {
                            ProjectRepositoryState.fromProcessState(processState).clearForNextSession();
                        }

                        CloudDebugProcessState state = processState;
                        CloudAttachDialog attachDialog = new CloudAttachDialog(session.getProject(), null);
                        attachDialog.setInputState(state);
                        DialogManager.show(attachDialog);
                        state = attachDialog.getResultState();

                        ProjectRepositoryValidator validator = null;
                        if (state != null) {
                            validator = new ProjectRepositoryValidator(state);
                        }
                        if (!attachDialog.isOK() || state == null || !validator.isValidDebuggee()) {
                            throw new RunCanceledByUserException();
                        }

                        if (environment.getRunnerAndConfigurationSettings() != null
                                && environment.getRunnerAndConfigurationSettings()
                                        .getConfiguration() instanceof CloudDebugRunConfiguration) {
                            CloudDebugRunConfiguration config = (CloudDebugRunConfiguration) environment
                                    .getRunnerAndConfigurationSettings().getConfiguration();
                            // State is only stored in the run config between active sessions.
                            // Otherwise, the background watcher may hit a check during debug session startup.
                            config.setProcessState(null);
                        }

                        CloudDebugProcess process = new CloudDebugProcess(session);
                        process.initialize(state);
                        return process;
                    }
                });

        RunnerLayoutUi ui = debugSession.getUI();
        if (ui instanceof DataProvider) {
            final RunnerContentUi contentUi = (RunnerContentUi) ((DataProvider) ui)
                    .getData(RunnerContentUi.KEY.getName());
            final Project project = debugSession.getProject();

            if (contentUi != null) {
                ApplicationManager.getApplication().invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (project.isOpen() && !project.isDisposed()) {
                            contentUi.restoreLayout();
                        }
                    }
                });
            }
        }

        return debugSession.getRunContentDescriptor();
    }

    private void ensureSingleDebugSession(Project project) throws RunCanceledByUserException {

        List<CloudDebugProcessState> backgroundSessions = getBackgroundDebugStates(project);
        if (backgroundSessions.size() > 0) {
            for (CloudDebugProcessState cdps : backgroundSessions) {
                cdps.setListenInBackground(false);
            }
        }

        List<CloudDebugProcess> activeDebugProcesses = getActiveDebugProcesses(project);
        if (activeDebugProcesses.size() > 0) {
            int result = Messages.showOkCancelDialog(project,
                    GctBundle.getString("clouddebug.stop.and.create.new.session"),
                    GctBundle.getString("clouddebug.message.title"), GoogleCloudToolsIcons.STACKDRIVER_DEBUGGER);
            if (result == Messages.OK) {
                for (CloudDebugProcess cdb : activeDebugProcesses) {
                    cdb.getProcessHandler().detachProcess();
                }
            } else {
                throw new RunCanceledByUserException();
            }
        }
    }

    private List<CloudDebugProcessState> getBackgroundDebugStates(Project project) {

        List<CloudDebugProcessState> states = Lists.newArrayList();

        RunManager manager = RunManager.getInstance(project);
        for (final RunnerAndConfigurationSettings config : manager.getAllSettings()) {
            if (config.getConfiguration() instanceof CloudDebugRunConfiguration) {
                final CloudDebugRunConfiguration cloudConfig = (CloudDebugRunConfiguration) config
                        .getConfiguration();
                CloudDebugProcessState processState = cloudConfig.getProcessState();
                if (processState != null && processState.isListenInBackground()) {
                    states.add(processState);
                }
            }
        }
        return states;
    }

    private List<CloudDebugProcess> getActiveDebugProcesses(Project project) {

        List<CloudDebugProcess> processes = Lists.newArrayList();

        for (XDebugSession session : XDebuggerManager.getInstance(project).getDebugSessions()) {
            if (session.getDebugProcess() instanceof CloudDebugProcess) {
                processes.add((CloudDebugProcess) session.getDebugProcess());
            }
        }
        return processes;
    }
}