org.sonar.server.debt.DebtModelPluginRepository Maven / Gradle / Ivy
/*
* SonarQube
* Copyright (C) 2009-2018 SonarSource SA
* mailto:info AT sonarsource DOT 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 02110-1301, USA.
*/
package org.sonar.server.debt;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.picocontainer.Startable;
import org.sonar.api.Plugin;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
import static com.google.common.collect.Lists.newArrayList;
/**
* This class is used to find which technical debt model XML files exist in the Sonar instance.
*
* Those XML files are provided by language plugins that embed their own contribution to the definition of the Technical debt model.
* They must be located in the classpath of those language plugins, more specifically in the "com.sonar.sqale" package, and
* they must be named "-model.xml".
*
*/
@ServerSide
@ComputeEngineSide
public class DebtModelPluginRepository implements Startable {
public static final String DEFAULT_MODEL = "technical-debt";
private static final String XML_FILE_SUFFIX = "-model.xml";
private static final String XML_FILE_PREFIX = "com/sonar/sqale/";
private String xmlFilePrefix;
private PluginRepository pluginRepository;
private Map contributingPluginKeyToClassLoader;
public DebtModelPluginRepository(PluginRepository pluginRepository) {
this.pluginRepository = pluginRepository;
this.xmlFilePrefix = XML_FILE_PREFIX;
}
@VisibleForTesting
DebtModelPluginRepository(PluginRepository pluginRepository, String xmlFilePrefix) {
this.pluginRepository = pluginRepository;
this.xmlFilePrefix = xmlFilePrefix;
}
@VisibleForTesting
DebtModelPluginRepository(Map contributingPluginKeyToClassLoader, String xmlFilePrefix) {
this.contributingPluginKeyToClassLoader = contributingPluginKeyToClassLoader;
this.xmlFilePrefix = xmlFilePrefix;
}
/**
* {@inheritDoc}
*/
@Override
public void start() {
findAvailableXMLFiles();
}
private void findAvailableXMLFiles() {
if (contributingPluginKeyToClassLoader == null) {
contributingPluginKeyToClassLoader = Maps.newTreeMap();
// Add default model
contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
String pluginKey = pluginInfo.getKey();
Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
ClassLoader classLoader = plugin.getClass().getClassLoader();
if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
}
}
}
contributingPluginKeyToClassLoader = Collections.unmodifiableMap(contributingPluginKeyToClassLoader);
}
@VisibleForTesting
String getXMLFilePath(String model) {
return xmlFilePrefix + model + XML_FILE_SUFFIX;
}
/**
* Returns the list of plugins that can contribute to the technical debt model.
*
* @return the list of plugin keys
*/
public Collection getContributingPluginList() {
return newArrayList(contributingPluginKeyToClassLoader.keySet());
}
/**
* Creates a new {@link java.io.Reader} for the XML file that contains the model contributed by the given plugin.
*
* @param pluginKey the key of the plugin that contributes the XML file
* @return the reader, that must be closed once its use is finished.
*/
public Reader createReaderForXMLFile(String pluginKey) {
ClassLoader classLoader = contributingPluginKeyToClassLoader.get(pluginKey);
String xmlFilePath = getXMLFilePath(pluginKey);
return new InputStreamReader(classLoader.getResourceAsStream(xmlFilePath), StandardCharsets.UTF_8);
}
@VisibleForTesting
Map getContributingPluginKeyToClassLoader() {
return contributingPluginKeyToClassLoader;
}
/**
* {@inheritDoc}
*/
@Override
public void stop() {
// Nothing to do
}
}