org.sonarlint.intellij.tasks.ServerUpdateTask.java Source code

Java tutorial

Introduction

Here is the source code for org.sonarlint.intellij.tasks.ServerUpdateTask.java

Source

/*
 * SonarLint for IntelliJ IDEA
 * Copyright (C) 2015 SonarSource
 * sonarlint@sonarsource.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonarlint.intellij.tasks;

import com.intellij.history.utils.RunnableAdapter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.sonarlint.intellij.config.global.SonarQubeServer;
import org.sonarlint.intellij.issue.IssueManager;
import org.sonarlint.intellij.trigger.SonarLintSubmitter;
import org.sonarlint.intellij.trigger.TriggerType;
import org.sonarlint.intellij.ui.SonarLintConsole;
import org.sonarlint.intellij.util.GlobalLogOutput;
import org.sonarlint.intellij.util.SonarLintUtils;
import org.sonarlint.intellij.util.TaskProgressMonitor;
import org.sonarsource.sonarlint.core.client.api.common.LogOutput;
import org.sonarsource.sonarlint.core.client.api.connected.ConnectedSonarLintEngine;
import org.sonarsource.sonarlint.core.client.api.connected.ServerConfiguration;
import org.sonarsource.sonarlint.core.client.api.connected.SonarAnalyzer;
import org.sonarsource.sonarlint.core.client.api.connected.UpdateResult;
import org.sonarsource.sonarlint.core.client.api.exceptions.CanceledException;
import org.sonarsource.sonarlint.core.plugin.Version;

public class ServerUpdateTask {
    private static final Logger LOGGER = Logger.getInstance(ServerUpdateTask.class);
    private final ConnectedSonarLintEngine engine;
    private final SonarQubeServer server;
    private final Map<String, List<Project>> projectsPerModule;
    private final boolean onlyModules;
    private final GlobalLogOutput log;

    public ServerUpdateTask(ConnectedSonarLintEngine engine, SonarQubeServer server,
            Map<String, List<Project>> projectsPerModule, boolean onlyModules) {
        this.engine = engine;
        this.server = server;
        this.projectsPerModule = projectsPerModule;
        this.onlyModules = onlyModules;
        this.log = GlobalLogOutput.get();
    }

    public Task.Modal asModal() {
        return new Task.Modal(null, "Updating SonarQube server '" + server.getName() + "'", true) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                ServerUpdateTask.this.run(indicator);
            }
        };
    }

    public Task.Backgroundable asBackground() {
        return new Task.Backgroundable(null, "Updating SonarQube server '" + server.getName() + "'", true,
                PerformInBackgroundOption.ALWAYS_BACKGROUND) {
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                ServerUpdateTask.this.run(indicator);
            }
        };
    }

    public void run(@NotNull ProgressIndicator indicator) {
        indicator.setText("Fetching data...");

        try {
            TaskProgressMonitor monitor = new TaskProgressMonitor(indicator);
            ServerConfiguration serverConfiguration = SonarLintUtils.getServerConfiguration(server);

            if (!onlyModules) {
                UpdateResult updateResult = engine.update(serverConfiguration, monitor);
                Collection<SonarAnalyzer> tooOld = updateResult.analyzers().stream()
                        .filter(SonarAnalyzer::sonarlintCompatible).filter(ServerUpdateTask::tooOld)
                        .collect(Collectors.toList());
                if (!tooOld.isEmpty()) {
                    ApplicationManager.getApplication().invokeAndWait(() -> Messages
                            .showWarningDialog(buildMinimumVersionFailMessage(tooOld), "Analyzers Not Loaded"),
                            ModalityState.any());
                }
                log.log("Server binding '" + server.getName() + "' updated", LogOutput.Level.INFO);
            }

            updateModules(serverConfiguration, monitor);

        } catch (CanceledException e) {
            LOGGER.info("Update of server '" + server.getName() + "' was cancelled");
            log.log("Update of server '" + server.getName() + "' was cancelled", LogOutput.Level.INFO);
        } catch (Exception e) {
            LOGGER.info("Error updating from server '" + server.getName() + "'", e);
            final String msg = (e.getMessage() != null) ? e.getMessage()
                    : ("Failed to update binding for server configuration '" + server.getName() + "'");
            ApplicationManager.getApplication().invokeAndWait(new RunnableAdapter() {
                @Override
                public void doRun() throws Exception {
                    Messages.showErrorDialog((Project) null, msg, "Update Failed");
                }
            }, ModalityState.any());
        }
    }

    private static String buildMinimumVersionFailMessage(Collection<SonarAnalyzer> failingAnalyzers) {
        StringBuilder builder = new StringBuilder();
        builder.append("The following plugins do not meet the required minimum versions, please upgrade them: ");

        boolean first = true;
        for (SonarAnalyzer p : failingAnalyzers) {
            if (!first) {
                builder.append(",");
            } else {
                first = false;
            }
            builder.append(p.key()).append(" (installed: ").append(p.version()).append(", minimum: ")
                    .append(p.minimumVersion()).append(")");
        }

        return builder.toString();
    }

    private static boolean tooOld(SonarAnalyzer analyzer) {
        if (analyzer.minimumVersion() != null && analyzer.version() != null) {
            Version minimum = Version.create(analyzer.minimumVersion());
            Version version = Version.create(analyzer.version());
            return version.compareTo(minimum) < 0;
        }
        return false;
    }

    private void updateModules(ServerConfiguration serverConfiguration, TaskProgressMonitor monitor) {
        //here we assume that server is updated, or this won't work
        final Set<String> existingProjectKeys = engine.allModulesByKey().keySet();
        final Set<String> invalidModules = new HashSet<>();

        for (Map.Entry<String, List<Project>> entry : projectsPerModule.entrySet()) {
            String moduleKey = entry.getKey();
            if (existingProjectKeys.contains(moduleKey)) {
                updateModule(serverConfiguration, moduleKey, entry.getValue(), monitor);
            } else {
                invalidModules.add(moduleKey);
            }
        }

        if (!projectsPerModule.isEmpty() && !invalidModules.isEmpty()) {
            log.log("The following modules could not be updated because they don't exist in the SonarQube server: "
                    + invalidModules.toString(), LogOutput.Level.WARN);

            ApplicationManager.getApplication().invokeLater(new RunnableAdapter() {
                @Override
                public void doRun() throws Exception {
                    Messages.showWarningDialog((Project) null,
                            "The following modules could not be updated because they don't exist in the SonarQube server: "
                                    + invalidModules.toString(),
                            "Modules Not Updated");
                }
            }, ModalityState.any());
        }
    }

    private void updateModule(ServerConfiguration serverConfiguration, String moduleKey, List<Project> projects,
            TaskProgressMonitor monitor) {
        try {
            engine.updateModule(serverConfiguration, moduleKey, monitor);
            log.log("Module '" + moduleKey + "' in server binding '" + server.getName() + "' updated",
                    LogOutput.Level.INFO);
            projects.forEach(ServerUpdateTask::analyzeOpenFiles);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            // in case of error, show a message box and keep updating other modules
            final String msg = (e.getMessage() != null) ? e.getMessage()
                    : ("Failed to update binding for server configuration '" + server.getName() + "'");
            ApplicationManager.getApplication().invokeLater(new RunnableAdapter() {
                @Override
                public void doRun() throws Exception {
                    Messages.showErrorDialog((Project) null, msg, "Update Failed");
                }
            }, ModalityState.any());
        }
    }

    private static void analyzeOpenFiles(Project project) {
        SonarLintConsole console = SonarLintConsole.get(project);
        console.info("Clearing all issues because binding was updated");

        IssueManager store = SonarLintUtils.get(project, IssueManager.class);
        store.clear();

        SonarLintSubmitter submitter = SonarLintUtils.get(project, SonarLintSubmitter.class);
        submitter.submitOpenFilesAuto(TriggerType.BINDING_UPDATE);
    }
}