diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-02-03 05:23:14 +0300 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-02-03 07:04:37 +0300 |
commit | 683120ea7db3d766078c1bc253c37cc0af687f74 (patch) | |
tree | 29ef2a6d759f2793ca748b53843ec461331e779a /sonar-batch-bootstrapper/src | |
parent | 2bc382aaeace31072352a0b7e18c5878815a692a (diff) | |
download | sonarqube-683120ea7db3d766078c1bc253c37cc0af687f74.tar.gz sonarqube-683120ea7db3d766078c1bc253c37cc0af687f74.zip |
SONAR-2106: Improve sonar-batch-bootstrapper
* Add BootstrapClassLoader
* Instead of RuntimeException use BootstrapException
* Improve quality according to Sonar report
Diffstat (limited to 'sonar-batch-bootstrapper/src')
-rw-r--r-- | sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapClassLoader.java | 93 | ||||
-rw-r--r-- | sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapException.java | 36 | ||||
-rw-r--r-- | sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/Bootstrapper.java (renamed from sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java) | 59 | ||||
-rw-r--r-- | sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java | 6 | ||||
-rw-r--r-- | sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapClassLoaderTest.java | 36 | ||||
-rw-r--r-- | sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapperTest.java (renamed from sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java) | 9 |
6 files changed, 212 insertions, 27 deletions
diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapClassLoader.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapClassLoader.java new file mode 100644 index 00000000000..c61a238df04 --- /dev/null +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapClassLoader.java @@ -0,0 +1,93 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Special {@link URLClassLoader} to execute Sonar, which restricts loading from parent. + */ +public class BootstrapClassLoader extends URLClassLoader { + + private String[] unmaskedPackages; + + public BootstrapClassLoader(ClassLoader parent, String... unmaskedPackages) { + super(new URL[0], parent); + this.unmaskedPackages = unmaskedPackages; + } + + /** + * {@inheritDoc} Visibility of a method has been relaxed to public. + */ + @Override + public void addURL(URL url) { + super.addURL(url); + } + + /** + * {@inheritDoc} Visibility of a method has been relaxed to public. + */ + @Override + public Class<?> findClass(String name) throws ClassNotFoundException { + return super.findClass(name); + } + + /** + * @return true, if class can be loaded from parent ClassLoader + */ + boolean canLoadFromParent(String name) { + for (String pkg : unmaskedPackages) { + if (name.startsWith(pkg + ".")) { + return true; + } + } + return false; + } + + /** + * Same behavior as in {@link URLClassLoader#loadClass(String, boolean)}, except loading from parent. + */ + @Override + protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { + // First, check if the class has already been loaded + Class<?> c = findLoadedClass(name); + if (c == null) { + try { + // Load from parent + if ((getParent() != null) && canLoadFromParent(name)) { + c = getParent().loadClass(name); + } else { + // Load from system + c = getSystemClassLoader().loadClass(name); + } + } catch (ClassNotFoundException e) { + // If still not found, then invoke findClass in order + // to find the class. + c = findClass(name); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + +} diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapException.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapException.java new file mode 100644 index 00000000000..8b75b61c97a --- /dev/null +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapException.java @@ -0,0 +1,36 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +public class BootstrapException extends RuntimeException { + + public BootstrapException(String message) { + super(message); + } + + public BootstrapException(Throwable cause) { + super(cause); + } + + public BootstrapException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/Bootstrapper.java index eead8dc6d5e..065c193c7d2 100644 --- a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BatchDownloader.java +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/Bootstrapper.java @@ -21,11 +21,12 @@ package org.sonar.batch.bootstrapper; import java.io.*; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; -public class BatchDownloader { +public class Bootstrapper { private static final String VERSION_PATH = "/api/server/version"; private static final String BATCH_PATH = "/batch/"; @@ -33,10 +34,13 @@ public class BatchDownloader { public static final int CONNECT_TIMEOUT_MILLISECONDS = 30000; public static final int READ_TIMEOUT_MILLISECONDS = 60000; + private File bootDir; private String serverUrl; private String serverVersion; - public BatchDownloader(String serverUrl) { + public Bootstrapper(String serverUrl, File workDir) { + bootDir = new File(workDir, "batch"); + bootDir.mkdirs(); if (serverUrl.endsWith("/")) { this.serverUrl = serverUrl.substring(0, serverUrl.length() - 1); } else { @@ -59,33 +63,34 @@ public class BatchDownloader { try { serverVersion = remoteContent(VERSION_PATH); } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); + throw new BootstrapException(e.getMessage(), e); } } return serverVersion; } /** + * Download batch files from server and creates {@link BootstrapClassLoader}. * To use this method version of Sonar should be at least 2.6. * - * @return list of downloaded files + * @param urls additional URLs for loading classes and resources + * @param parent parent ClassLoader + * @param unmaskedPackages only classes and resources from those packages would be available for loading from parent */ - public List<File> downloadBatchFiles(File toDir) { - try { - List<File> files = new ArrayList<File>(); - - String libs = remoteContent(BATCH_PATH); - - for (String lib : libs.split(",")) { - File file = new File(toDir, lib); - remoteContentToFile(BATCH_PATH + lib, file); - files.add(file); + public BootstrapClassLoader createClassLoader(URL[] urls, ClassLoader parent, String... unmaskedPackages) { + BootstrapClassLoader classLoader = new BootstrapClassLoader(parent, unmaskedPackages); + List<File> files = downloadBatchFiles(); + for (URL url : urls) { + classLoader.addURL(url); + } + for (File file : files) { + try { + classLoader.addURL(file.toURI().toURL()); + } catch (MalformedURLException e) { + throw new BootstrapException(e); } - - return files; - } catch (Exception e) { - throw new RuntimeException(e); } + return classLoader; } private void remoteContentToFile(String path, File toFile) { @@ -97,10 +102,10 @@ public class BatchDownloader { output = new FileOutputStream(toFile, false); input = connection.getInputStream(); BootstrapperIOUtils.copyLarge(input, output); - } catch (Exception e) { + } catch (IOException e) { BootstrapperIOUtils.closeQuietly(output); BootstrapperIOUtils.deleteFileQuietly(toFile); - throw new RuntimeException("Fail to download the file: " + fullUrl, e); + throw new BootstrapException("Fail to download the file: " + fullUrl, e); } finally { BootstrapperIOUtils.closeQuietly(input); BootstrapperIOUtils.closeQuietly(output); @@ -133,4 +138,18 @@ public class BatchDownloader { return connection; } + private List<File> downloadBatchFiles() { + try { + List<File> files = new ArrayList<File>(); + String libs = remoteContent(BATCH_PATH); + for (String lib : libs.split(",")) { + File file = new File(bootDir, lib); + remoteContentToFile(BATCH_PATH + lib, file); + files.add(file); + } + return files; + } catch (Exception e) { + throw new BootstrapException(e); + } + } } diff --git a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java index e7d4ec42e1a..d400bc8c40d 100644 --- a/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java +++ b/sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapperIOUtils.java @@ -21,9 +21,10 @@ package org.sonar.batch.bootstrapper; import java.io.*; -final class BootstrapperIOUtils { +public final class BootstrapperIOUtils { private BootstrapperIOUtils() { + // only static methods } /** @@ -39,8 +40,7 @@ final class BootstrapperIOUtils { if (closeable != null) { closeable.close(); } - } catch (IOException ioe) { - // ignore + } catch (IOException ioe) { // NOSONAR } } diff --git a/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapClassLoaderTest.java b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapClassLoaderTest.java new file mode 100644 index 00000000000..b8a13d50173 --- /dev/null +++ b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapClassLoaderTest.java @@ -0,0 +1,36 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.batch.bootstrapper; + +import org.junit.Test; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class BootstrapClassLoaderTest { + + @Test + public void shouldRestrictLoadingFromParent() throws Exception { + BootstrapClassLoader classLoader = new BootstrapClassLoader(getClass().getClassLoader(), "org.sonar.ant"); + assertThat(classLoader.canLoadFromParent("org.sonar.ant.Launcher"), is(true)); + assertThat(classLoader.canLoadFromParent("org.objectweb.asm.ClassVisitor"), is(false)); + } + +} diff --git a/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapperTest.java index 1822a53f014..945940a4873 100644 --- a/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BatchDownloaderTest.java +++ b/sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapperTest.java @@ -21,28 +21,29 @@ package org.sonar.batch.bootstrapper; import org.junit.Test; +import java.io.File; import java.io.IOException; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -public class BatchDownloaderTest { +public class BootstrapperTest { @Test public void shouldRemoveLastUrlSlash() { - BatchDownloader bootstrapper = new BatchDownloader("http://test/"); + Bootstrapper bootstrapper = new Bootstrapper("http://test/", new File("target")); assertThat(bootstrapper.getServerUrl(), is("http://test")); } @Test(expected = Exception.class) public void shouldFailIfCanNotConnectServer() { - BatchDownloader bootstrapper = new BatchDownloader("http://unknown.foo"); + Bootstrapper bootstrapper = new Bootstrapper("http://unknown.foo", new File("target")); bootstrapper.getServerVersion(); } @Test public void shouldReturnValidVersion() { - BatchDownloader bootstrapper = new BatchDownloader("http://test") { + Bootstrapper bootstrapper = new Bootstrapper("http://test", new File("target")) { @Override String remoteContent(String path) throws IOException { return "2.6"; |