org.sonar.server.plugins.ServerPluginJarsInstaller.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.plugins.ServerPluginJarsInstaller.java

Source

/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube 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.
 *
 * SonarQube 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  02110-1301, USA.
 */
package org.sonar.server.plugins;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.platform.Server;
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.core.plugins.DefaultPluginMetadata;
import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.updatecenter.common.PluginReferential;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ServerPluginJarsInstaller {

    private static final Logger LOG = LoggerFactory.getLogger(ServerPluginJarsInstaller.class);

    private final Server server;
    private final DefaultServerFileSystem fs;
    private final ServerPluginJarInstaller installer;
    private final Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap();
    private final ServerUpgradeStatus serverUpgradeStatus;
    private static final Set<String> BLACKLISTED_PLUGINS = new HashSet<String>(Arrays.asList("scmactivity"));

    public ServerPluginJarsInstaller(Server server, ServerUpgradeStatus serverUpgradeStatus,
            DefaultServerFileSystem fs, ServerPluginJarInstaller installer) {
        this.server = server;
        this.serverUpgradeStatus = serverUpgradeStatus;
        this.fs = fs;
        this.installer = installer;
    }

    public void install() {
        TimeProfiler profiler = new TimeProfiler().start("Install plugins");
        deleteTrash();
        loadInstalledPlugins();
        copyBundledPlugins();
        moveDownloadedPlugins();
        loadCorePlugins();
        deployPlugins();
        profiler.stop();
    }

    private void deleteTrash() {
        File trashDir = fs.getTrashPluginsDir();
        try {
            if (trashDir.exists()) {
                FileUtils.deleteDirectory(trashDir);
            }
        } catch (IOException e) {
            throw new IllegalStateException("Fail to clean the plugin trash directory: " + trashDir, e);
        }
    }

    private void loadInstalledPlugins() {
        for (File file : fs.getUserPlugins()) {
            DefaultPluginMetadata metadata = installer.extractMetadata(file, false);
            if (StringUtils.isNotBlank(metadata.getKey())) {
                loadInstalledPlugin(metadata);
            }
        }
    }

    private void loadInstalledPlugin(DefaultPluginMetadata metadata) {
        if (BLACKLISTED_PLUGINS.contains(metadata.getKey())) {
            LOG.warn("Plugin {} is blacklisted. Please uninstall it.", metadata.getName());
        } else {
            PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
            if (existing != null) {
                throw MessageException.of(String.format("Found two files for the same plugin '%s': %s and %s",
                        metadata.getKey(), metadata.getFile().getName(), existing.getFile().getName()));
            }
        }
    }

    private void moveDownloadedPlugins() {
        if (fs.getDownloadedPluginsDir().exists()) {
            Collection<File> sourceFiles = FileUtils.listFiles(fs.getDownloadedPluginsDir(), new String[] { "jar" },
                    false);
            for (File sourceFile : sourceFiles) {
                overridePlugin(sourceFile, true);
            }
        }
    }

    private void copyBundledPlugins() {
        if (serverUpgradeStatus.isFreshInstall()) {
            for (File sourceFile : fs.getBundledPlugins()) {
                DefaultPluginMetadata metadata = installer.extractMetadata(sourceFile, false);
                // lib/bundled-plugins should be copied only if the plugin is not already
                // available in extensions/plugins
                if (!pluginByKeys.containsKey(metadata.getKey())) {
                    overridePlugin(sourceFile, false);
                }
            }
        }
    }

    private void overridePlugin(File sourceFile, boolean deleteSource) {
        File destDir = fs.getUserPluginsDir();
        File destFile = new File(destDir, sourceFile.getName());
        if (destFile.exists()) {
            // plugin with same filename already installed
            FileUtils.deleteQuietly(destFile);
        }

        try {
            if (deleteSource) {
                FileUtils.moveFile(sourceFile, destFile);
            } else {
                FileUtils.copyFile(sourceFile, destFile, true);
            }
        } catch (IOException e) {
            LOG.error(String.format("Fail to move or copy plugin: %s to %s", sourceFile.getAbsolutePath(),
                    destFile.getAbsolutePath()), e);
        }

        DefaultPluginMetadata metadata = installer.extractMetadata(destFile, false);
        if (StringUtils.isNotBlank(metadata.getKey())) {
            PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
            if (existing != null) {
                if (!existing.getFile().getName().equals(destFile.getName())) {
                    FileUtils.deleteQuietly(existing.getFile());
                }
                LOG.info("Plugin " + metadata.getKey() + " replaced by new version");
            }
        }
    }

    private void loadCorePlugins() {
        for (File file : fs.getCorePlugins()) {
            DefaultPluginMetadata metadata = installer.extractMetadata(file, true);
            PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
            if (existing != null) {
                throw new IllegalStateException("Found two plugins with the same key '" + metadata.getKey() + "': "
                        + metadata.getFile().getName() + " and " + existing.getFile().getName());
            }
        }
    }

    public void uninstall(String pluginKey) {
        for (String key : getPluginReferential().findLastReleasesWithDependencies(pluginKey)) {
            uninstallPlugin(key);
        }
    }

    private void uninstallPlugin(String pluginKey) {
        PluginMetadata metadata = pluginByKeys.get(pluginKey);
        if (metadata != null && !metadata.isCore()) {
            try {
                File masterFile = new File(fs.getUserPluginsDir(), metadata.getFile().getName());
                FileUtils.moveFileToDirectory(masterFile, fs.getTrashPluginsDir(), true);
            } catch (IOException e) {
                throw new IllegalStateException("Fail to uninstall plugin: " + pluginKey, e);
            }
        }
    }

    public List<String> getUninstalls() {
        List<String> names = Lists.newArrayList();
        if (fs.getTrashPluginsDir().exists()) {
            List<File> files = (List<File>) FileUtils.listFiles(fs.getTrashPluginsDir(), new String[] { "jar" },
                    false);
            for (File file : files) {
                names.add(file.getName());
            }
        }
        return names;
    }

    public void cancelUninstalls() {
        if (fs.getTrashPluginsDir().exists()) {
            List<File> files = (List<File>) FileUtils.listFiles(fs.getTrashPluginsDir(), new String[] { "jar" },
                    false);
            for (File file : files) {
                try {
                    FileUtils.moveFileToDirectory(file, fs.getUserPluginsDir(), false);
                } catch (IOException e) {
                    throw new IllegalStateException("Fail to cancel plugin uninstalls", e);
                }
            }
        }
    }

    private void deployPlugins() {
        for (PluginMetadata metadata : pluginByKeys.values()) {
            deploy((DefaultPluginMetadata) metadata);
        }
    }

    private void deploy(DefaultPluginMetadata plugin) {
        LOG.info("Deploy plugin {}", Joiner.on(" / ").skipNulls().join(plugin.getName(), plugin.getVersion(),
                plugin.getImplementationBuild()));

        if (!plugin.isCompatibleWith(server.getVersion())) {
            throw MessageException.of(String.format(
                    "Plugin %s needs a more recent version of SonarQube than %s. At least %s is expected",
                    plugin.getKey(), server.getVersion(), plugin.getSonarVersion()));
        }

        try {
            File pluginDeployDir = new File(fs.getDeployedPluginsDir(), plugin.getKey());
            FileUtils.forceMkdir(pluginDeployDir);
            FileUtils.cleanDirectory(pluginDeployDir);

            installer.installToDir(plugin, pluginDeployDir);
        } catch (IOException e) {
            throw new IllegalStateException("Fail to deploy the plugin " + plugin, e);
        }
    }

    public Collection<PluginMetadata> getMetadata() {
        return pluginByKeys.values();
    }

    public PluginMetadata getMetadata(String pluginKey) {
        return pluginByKeys.get(pluginKey);
    }

    private PluginReferential getPluginReferential() {
        return PluginReferentialMetadataConverter.getInstalledPluginReferential(getMetadata());
    }
}