Przeglądaj źródła

SONAR-1780:

* An exception should be thrown in case when two Sonar plugins try to use the same key
* Add message to log, when file with plugin was deleted
tags/2.6
Godin 13 lat temu
rodzic
commit
1006c3556b

+ 45
- 24
sonar-server/src/main/java/org/sonar/server/plugins/PluginDeployer.java Wyświetl plik

import org.sonar.core.plugin.JpaPlugin; import org.sonar.core.plugin.JpaPlugin;
import org.sonar.core.plugin.JpaPluginDao; import org.sonar.core.plugin.JpaPluginDao;
import org.sonar.server.platform.DefaultServerFileSystem; import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.server.platform.ServerStartException;

import com.google.common.collect.Maps;


import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


public final class PluginDeployer implements ServerComponent { public final class PluginDeployer implements ServerComponent {


private DefaultServerFileSystem fileSystem; private DefaultServerFileSystem fileSystem;
private JpaPluginDao dao; private JpaPluginDao dao;
private PluginClassLoaders classloaders; private PluginClassLoaders classloaders;
private Map<String, PluginMetadata> pluginByKeys = new HashMap<String, PluginMetadata>();
private List<PluginMetadata> deprecatedPlugins = new ArrayList<PluginMetadata>();
private Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap();
private Map<String, PluginMetadata> deprecatedPlugins = Maps.newHashMap();


public PluginDeployer(Server server, DefaultServerFileSystem fileSystem, JpaPluginDao dao, PluginClassLoaders classloaders) { public PluginDeployer(Server server, DefaultServerFileSystem fileSystem, JpaPluginDao dao, PluginClassLoaders classloaders) {
this.server = server; this.server = server;
} }


private void deployDeprecatedPlugins() throws IOException { private void deployDeprecatedPlugins() throws IOException {
for (PluginMetadata deprecatedPlugin : deprecatedPlugins) {
if (deprecatedPlugin.getKey() != null && !pluginByKeys.containsKey(deprecatedPlugin.getKey())) {
for (PluginMetadata deprecatedPlugin : deprecatedPlugins.values()) {
PluginMetadata metadata = pluginByKeys.get(deprecatedPlugin.getKey());
if (metadata != null) {
FileUtils.deleteQuietly(deprecatedPlugin.getSourceFile());
Logs.INFO.info("Old plugin " + deprecatedPlugin.getFilename() + " replaced by new " + metadata.getFilename());
} else {
pluginByKeys.put(deprecatedPlugin.getKey(), deprecatedPlugin); pluginByKeys.put(deprecatedPlugin.getKey(), deprecatedPlugin);
deploy(deprecatedPlugin); deploy(deprecatedPlugin);

} else {
FileUtils.deleteQuietly(deprecatedPlugin.getSourceFile());
} }
} }
} }


private void loadCorePlugins() throws IOException { private void loadCorePlugins() throws IOException {
for (File file : fileSystem.getCorePlugins()) { for (File file : fileSystem.getCorePlugins()) {
registerPluginMetadata(file, true);
registerPluginMetadata(file, true, false);
} }
} }


private void loadUserPlugins() throws IOException { private void loadUserPlugins() throws IOException {
for (File file : fileSystem.getUserPlugins()) { for (File file : fileSystem.getUserPlugins()) {
registerPluginMetadata(file, false);
registerPluginMetadata(file, false, false);
} }
} }


private void moveAndLoadDownloadedPlugins() throws IOException { private void moveAndLoadDownloadedPlugins() throws IOException {
if (fileSystem.getDownloadedPluginsDir().exists()) { if (fileSystem.getDownloadedPluginsDir().exists()) {
Collection<File> jars = FileUtils.listFiles(fileSystem.getDownloadedPluginsDir(), new String[]{"jar"}, false);
Collection<File> jars = FileUtils.listFiles(fileSystem.getDownloadedPluginsDir(), new String[] { "jar" }, false);
for (File jar : jars) { for (File jar : jars) {
File movedJar = moveDownloadedFile(jar); File movedJar = moveDownloadedFile(jar);
registerPluginMetadata(movedJar, false);
registerPluginMetadata(movedJar, false, true);
} }
} }
} }
return new File(fileSystem.getUserPluginsDir(), jar.getName()); return new File(fileSystem.getUserPluginsDir(), jar.getName());


} catch (IOException e) { } catch (IOException e) {
LOG.error("Fail to move the downloaded file:" + jar.getAbsolutePath(), e);
LOG.error("Fail to move the downloaded file: " + jar.getAbsolutePath(), e);
return null; return null;
} }
} }


private void registerPluginMetadata(File file, boolean corePlugin) throws IOException {
private void registerPluginMetadata(File file, boolean corePlugin, boolean canDeleteOld) throws IOException {
PluginMetadata metadata = PluginMetadata.createFromJar(file, corePlugin); PluginMetadata metadata = PluginMetadata.createFromJar(file, corePlugin);
String pluginKey = metadata.getKey(); String pluginKey = metadata.getKey();
if (pluginKey != null) { if (pluginKey != null) {
PluginMetadata existing = pluginByKeys.get(pluginKey);
if (existing != null) {
FileUtils.deleteQuietly(existing.getSourceFile());
pluginByKeys.remove(pluginKey);
}
pluginByKeys.put(pluginKey, metadata);

registerPluginMetadata(pluginByKeys, file, metadata, canDeleteOld);
} else if (metadata.isOldManifest()) { } else if (metadata.isOldManifest()) {
loadDeprecatedPlugin(metadata); loadDeprecatedPlugin(metadata);
deprecatedPlugins.add(metadata);
registerPluginMetadata(deprecatedPlugins, file, metadata, canDeleteOld);
} }
} }


private void registerPluginMetadata(Map<String, PluginMetadata> map, File file, PluginMetadata metadata, boolean canDeleteOld) {
String pluginKey = metadata.getKey();
PluginMetadata existing = map.get(pluginKey);
if (existing != null) {
if (canDeleteOld) {
FileUtils.deleteQuietly(existing.getSourceFile());
map.remove(pluginKey);
Logs.INFO.info("Old plugin " + existing.getFilename() + " replaced by new " + metadata.getFilename());
} else {
throw new ServerStartException("Found two plugins with the same key '" + pluginKey + "': "
+ metadata.getFilename() + " and "
+ existing.getFilename());
}
}
map.put(metadata.getKey(), metadata);
}

private void loadDeprecatedPlugin(PluginMetadata plugin) throws IOException { private void loadDeprecatedPlugin(PluginMetadata plugin) throws IOException {
// URLClassLoader locks files on Windows // URLClassLoader locks files on Windows
// => copy the file before in a temp directory // => copy the file before in a temp directory


String mainClass = plugin.getMainClass(); String mainClass = plugin.getMainClass();
try { try {
URLClassLoader pluginClassLoader = URLClassLoader.newInstance(new URL[]{tempFile.toURI().toURL()}, getClass().getClassLoader());
URLClassLoader pluginClassLoader = URLClassLoader.newInstance(new URL[] { tempFile.toURI().toURL() }, getClass().getClassLoader());
Plugin pluginInstance = (Plugin) pluginClassLoader.loadClass(mainClass).newInstance(); Plugin pluginInstance = (Plugin) pluginClassLoader.loadClass(mainClass).newInstance();
plugin.setKey(pluginInstance.getKey()); plugin.setKey(pluginInstance.getKey());
plugin.setDescription(pluginInstance.getDescription()); plugin.setDescription(pluginInstance.getDescription());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("The plugin main class can not be created: plugin=" + plugin.getFilename() + ", class=" + mainClass, e); throw new RuntimeException("The plugin main class can not be created: plugin=" + plugin.getFilename() + ", class=" + mainClass, e);
} }
}


if (StringUtils.isBlank(plugin.getKey())) {
throw new ServerStartException("Found plugin with empty key: " + plugin.getFilename());
}
}
} }

+ 19
- 7
sonar-server/src/test/java/org/sonar/server/plugins/PluginDeployerTest.java Wyświetl plik

import org.sonar.jpa.test.AbstractDbUnitTestCase; import org.sonar.jpa.test.AbstractDbUnitTestCase;
import org.sonar.server.platform.DefaultServerFileSystem; import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.server.platform.ServerImpl; import org.sonar.server.platform.ServerImpl;
import org.sonar.server.platform.ServerStartException;
import org.sonar.test.TestUtils; import org.sonar.test.TestUtils;


import java.io.File; import java.io.File;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.List; import java.util.List;


import static junit.framework.Assert.assertNotNull;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;


public class PluginDeployerTest extends AbstractDbUnitTestCase { public class PluginDeployerTest extends AbstractDbUnitTestCase {


@Rule @Rule
public TestName name = new TestName(); public TestName name = new TestName();
@Before @Before
public void start() throws ParseException { public void start() throws ParseException {
server = new ServerImpl("1", "2.2", new SimpleDateFormat("yyyy-MM-dd").parse("2010-05-18")); server = new ServerImpl("1", "2.2", new SimpleDateFormat("yyyy-MM-dd").parse("2010-05-18"));
deployer = new PluginDeployer(server, fileSystem, dao, classloaders); deployer = new PluginDeployer(server, fileSystem, dao, classloaders);
} }



@Test @Test
public void deployPlugin() throws IOException { public void deployPlugin() throws IOException {
setupData("shared"); setupData("shared");


// check that the plugin is registered in database // check that the plugin is registered in database
List<JpaPlugin> plugins = dao.getPlugins(); List<JpaPlugin> plugins = dao.getPlugins();
assertThat(plugins.size(), is(1)); // no more checkstyle
assertThat(plugins.size(), is(1)); // no more checkstyle
JpaPlugin plugin = plugins.get(0); JpaPlugin plugin = plugins.get(0);
assertThat(plugin.getName(), is("Foo")); assertThat(plugin.getName(), is("Foo"));
assertThat(plugin.getFiles().size(), is(1)); assertThat(plugin.getFiles().size(), is(1));


// check that the plugin is registered in database // check that the plugin is registered in database
List<JpaPlugin> plugins = dao.getPlugins(); List<JpaPlugin> plugins = dao.getPlugins();
assertThat(plugins.size(), is(1)); // no more checkstyle
assertThat(plugins.size(), is(1)); // no more checkstyle
JpaPlugin plugin = plugins.get(0); JpaPlugin plugin = plugins.get(0);
assertThat(plugin.getKey(), is("build-breaker")); assertThat(plugin.getKey(), is("build-breaker"));
assertThat(plugin.getFiles().size(), is(1)); assertThat(plugin.getFiles().size(), is(1));


// check that the plugin is registered in database // check that the plugin is registered in database
List<JpaPlugin> plugins = dao.getPlugins(); List<JpaPlugin> plugins = dao.getPlugins();
assertThat(plugins.size(), is(1)); // no more checkstyle
assertThat(plugins.size(), is(1)); // no more checkstyle
JpaPlugin plugin = plugins.get(0); JpaPlugin plugin = plugins.get(0);
assertThat(plugin.getFiles().size(), is(2)); assertThat(plugin.getFiles().size(), is(2));
JpaPluginFile pluginFile = plugin.getFiles().get(1); JpaPluginFile pluginFile = plugin.getFiles().get(1);


// check that the plugin is registered in database // check that the plugin is registered in database
List<JpaPlugin> plugins = dao.getPlugins(); List<JpaPlugin> plugins = dao.getPlugins();
assertThat(plugins.size(), is(0));
assertThat(plugins.size(), is(0));
}

@Test(expected = ServerStartException.class)
public void failIfTwoPluginsWithSameKey() throws IOException {
setupData("shared");
deployer.start();
}

@Test(expected = ServerStartException.class)
public void failIfTwoDeprecatedPluginsWithSameKey() throws IOException {
setupData("shared");
deployer.start();
} }


} }

BIN
sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/failIfTwoDeprecatedPluginsWithSameKey/extensions/plugins/sonar-build-breaker-plugin-0.1.jar Wyświetl plik


BIN
sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/failIfTwoDeprecatedPluginsWithSameKey/extensions/plugins/sonar-build-breaker-plugin-0.2.jar Wyświetl plik


BIN
sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/failIfTwoPluginsWithSameKey/extensions/plugins/foo-plugin1.jar Wyświetl plik


BIN
sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/failIfTwoPluginsWithSameKey/extensions/plugins/foo-plugin2.jar Wyświetl plik


Ładowanie…
Anuluj
Zapisz