summaryrefslogtreecommitdiffstats
path: root/sonar-batch-bootstrapper/src
diff options
context:
space:
mode:
authorEvgeny Mandrikov <mandrikov@gmail.com>2011-02-03 05:23:14 +0300
committerEvgeny Mandrikov <mandrikov@gmail.com>2011-02-03 07:04:37 +0300
commit683120ea7db3d766078c1bc253c37cc0af687f74 (patch)
tree29ef2a6d759f2793ca748b53843ec461331e779a /sonar-batch-bootstrapper/src
parent2bc382aaeace31072352a0b7e18c5878815a692a (diff)
downloadsonarqube-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.java93
-rw-r--r--sonar-batch-bootstrapper/src/main/java/org/sonar/batch/bootstrapper/BootstrapException.java36
-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.java6
-rw-r--r--sonar-batch-bootstrapper/src/test/java/org/sonar/batch/bootstrapper/BootstrapClassLoaderTest.java36
-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";