summaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2012-07-14 19:32:45 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2012-07-14 19:32:45 +0200
commit86706f9bae9c427f729484cd98b425cd25ae653e (patch)
treebdfb312769448b7adce876a37bf87bff3f5127a8 /sonar-plugin-api
parent28588545174b1c764b018daf943d65f6b3617b47 (diff)
downloadsonarqube-86706f9bae9c427f729484cd98b425cd25ae653e.tar.gz
sonarqube-86706f9bae9c427f729484cd98b425cd25ae653e.zip
Update Center improvements
* SONAR-3661 API: new component org.sonar.api.utils.UriReader * SONAR-3660 The property sonar.updatecenter.url must support local files * SONAR-3659 Availability of Update Center with non-RELEASE versions of Sonar * SONAR-2008 Enable updates from SNAPSHOT versions for plugins
Diffstat (limited to 'sonar-plugin-api')
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java21
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java147
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java59
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/UriReaderTest.java122
-rw-r--r--sonar-plugin-api/src/test/resources/org/sonar/api/utils/UriReaderTest/foo.txt1
5 files changed, 328 insertions, 22 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
index 1f99d62f46a..1f7b1c54613 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java
@@ -34,6 +34,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
+import java.nio.charset.Charset;
import java.util.List;
/**
@@ -41,7 +42,7 @@ import java.util.List;
*
* @since 2.2
*/
-public class HttpDownloader implements BatchComponent, ServerComponent {
+public class HttpDownloader implements UriReader.SchemeProcessor, BatchComponent, ServerComponent {
public static final int TIMEOUT_MILLISECONDS = 20 * 1000;
@@ -91,9 +92,13 @@ public class HttpDownloader implements BatchComponent, ServerComponent {
return Joiner.on(", ").join(descriptions);
}
+ public String description(URI uri) {
+ return String.format("%s (%s)", uri.toString(), getProxySynthesis(uri));
+ }
+
private void registerProxyCredentials(Settings settings) {
Authenticator.setDefault(new ProxyAuthenticator(settings.getString("http.proxyUser"), settings
- .getString("http.proxyPassword")));
+ .getString("http.proxyPassword")));
}
private boolean requiresProxyAuthentication(Settings settings) {
@@ -165,6 +170,18 @@ public class HttpDownloader implements BatchComponent, ServerComponent {
}
}
+ public String[] getSupportedSchemes() {
+ return new String[]{"http", "https"};
+ }
+
+ public byte[] readBytes(URI uri) {
+ return download(uri);
+ }
+
+ public String readString(URI uri, Charset charset) {
+ return downloadPlainText(uri, charset.name());
+ }
+
public InputStream openStream(URI uri) {
try {
HttpURLConnection connection = newHttpConnection(uri);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java
new file mode 100644
index 00000000000..105d984dfd8
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java
@@ -0,0 +1,147 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.io.Files;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Reads different types of URI. Supported schemes are http and file.
+ *
+ * @since 3.2
+ */
+public class UriReader implements BatchComponent, ServerComponent {
+
+ private final Map<String, SchemeProcessor> processorsByScheme = Maps.newHashMap();
+
+ public UriReader(SchemeProcessor[] processors) {
+ List<SchemeProcessor> allProcessors = Lists.asList(new FileProcessor(), processors);
+ for (SchemeProcessor processor : allProcessors) {
+ for (String scheme : processor.getSupportedSchemes()) {
+ processorsByScheme.put(scheme.toLowerCase(Locale.ENGLISH), processor);
+ }
+ }
+ }
+
+ /**
+ * Reads all bytes from uri. It throws an unchecked exception if an error occurs.
+ */
+ public byte[] readBytes(URI uri) {
+ return searchForSupportedProcessor(uri).readBytes(uri);
+ }
+
+ /**
+ * Reads all characters from uri, using the given character set.
+ * It throws an unchecked exception if an error occurs.
+ */
+ public String readString(URI uri, Charset charset) {
+ return searchForSupportedProcessor(uri).readString(uri, charset);
+ }
+
+ /**
+ * Opens an input stream over the given uri.
+ */
+ public InputStream openStream(URI uri) {
+ return searchForSupportedProcessor(uri).openStream(uri);
+ }
+
+ /**
+ * Returns a detailed description of the given uri. For example HTTP URIs are completed
+ * with the configured HTTP proxy.
+ */
+ public String description(URI uri) {
+ SchemeProcessor reader = searchForSupportedProcessor(uri);
+
+ return reader.description(uri);
+ }
+
+ @VisibleForTesting
+ SchemeProcessor searchForSupportedProcessor(URI uri) {
+ SchemeProcessor processor = processorsByScheme.get(uri.getScheme().toLowerCase(Locale.ENGLISH));
+ Preconditions.checkArgument(processor != null, "URI schema is not supported: " + uri.getScheme());
+ return processor;
+ }
+
+ static interface SchemeProcessor extends BatchComponent, ServerComponent {
+ String[] getSupportedSchemes();
+
+ byte[] readBytes(URI uri);
+
+ String readString(URI uri, Charset charset);
+
+ InputStream openStream(URI uri);
+
+ String description(URI uri);
+ }
+
+
+ /**
+ * This implementation is not exposed in API and is kept private.
+ */
+ private static class FileProcessor implements SchemeProcessor {
+
+ public String[] getSupportedSchemes() {
+ return new String[]{"file"};
+ }
+
+ public byte[] readBytes(URI uri) {
+ try {
+ return Files.toByteArray(new File(uri));
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public String readString(URI uri, Charset charset) {
+ try {
+ return Files.toString(new File(uri), charset);
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public InputStream openStream(URI uri) {
+ try {
+ return Files.newInputStreamSupplier(new File(uri)).getInput();
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public String description(URI uri) {
+ return new File(uri).getAbsolutePath();
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
index f72d9b6843f..c8bc80d83e2 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java
@@ -19,6 +19,7 @@
*/
package org.sonar.api.utils;
+import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.SystemUtils;
@@ -31,15 +32,14 @@ import org.sonar.api.platform.Server;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.net.*;
import java.util.Arrays;
import java.util.Properties;
-import static org.hamcrest.Matchers.greaterThan;
+import static org.fest.assertions.Assertions.assertThat;
import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
-import static org.junit.internal.matchers.StringContains.containsString;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -161,21 +161,28 @@ public class HttpDownloaderTest {
}
@Test
- public void downloadBytes() throws URISyntaxException {
- byte[] bytes = new HttpDownloader(new Settings()).download(new URI(baseUrl));
- assertThat(bytes.length, greaterThan(10));
+ public void downloadBytes() throws Exception {
+ byte[] bytes = new HttpDownloader(new Settings()).readBytes(new URI(baseUrl));
+ assertThat(bytes.length).isGreaterThan(10);
}
@Test
- public void downloadPlainText() throws URISyntaxException {
- String text = new HttpDownloader(new Settings()).downloadPlainText(new URI(baseUrl), "UTF-8");
- assertThat(text.length(), greaterThan(10));
+ public void readString() throws Exception {
+ String text = new HttpDownloader(new Settings()).readString(new URI(baseUrl), Charsets.UTF_8);
+ assertThat(text.length()).isGreaterThan(10);
+ }
+
+ @Test
+ public void openStream() throws Exception {
+ InputStream input = new HttpDownloader(new Settings()).openStream(new URI(baseUrl));
+ assertThat(IOUtils.toByteArray(input).length).isGreaterThan(10);
+ IOUtils.closeQuietly(input);
}
@Test(expected = SonarException.class)
- public void failIfServerDown() throws URISyntaxException {
+ public void failIfServerDown() throws Exception {
// I hope that the port 1 is not used !
- new HttpDownloader(new Settings()).download(new URI("http://localhost:1/unknown"));
+ new HttpDownloader(new Settings()).readBytes(new URI("http://localhost:1/unknown"));
}
@Test
@@ -186,8 +193,8 @@ public class HttpDownloaderTest {
File toFile = new File(toDir, "downloadToFile.txt");
new HttpDownloader(new Settings()).download(new URI(baseUrl), toFile);
- assertThat(toFile.exists(), is(true));
- assertThat(toFile.length(), greaterThan(10l));
+ assertThat(toFile).exists();
+ assertThat(toFile.length()).isGreaterThan(10l);
}
@Test
@@ -201,7 +208,7 @@ public class HttpDownloaderTest {
// I hope that the port 1 is not used !
new HttpDownloader(new Settings()).download(new URI("http://localhost:1/unknown"), toFile);
} catch (SonarException e) {
- assertThat(toFile.exists(), is(false));
+ assertThat(toFile).doesNotExist();
}
}
@@ -210,30 +217,42 @@ public class HttpDownloaderTest {
Server server = mock(Server.class);
when(server.getVersion()).thenReturn("2.2");
- byte[] bytes = new HttpDownloader(server, new Settings()).download(new URI(baseUrl));
+ byte[] bytes = new HttpDownloader(server, new Settings()).readBytes(new URI(baseUrl));
Properties props = new Properties();
props.load(IOUtils.toInputStream(new String(bytes)));
- assertThat(props.getProperty("agent"), is("Sonar 2.2"));
+ assertThat(props.getProperty("agent")).isEqualTo("Sonar 2.2");
}
@Test
public void followRedirect() throws URISyntaxException {
- byte[] bytes = new HttpDownloader(new Settings()).download(new URI(baseUrl + "/redirect/"));
- assertThat(new String(bytes), containsString("count"));
+ byte[] bytes = new HttpDownloader(new Settings()).readBytes(new URI(baseUrl + "/redirect/"));
+ assertThat(new String(bytes)).contains("count");
}
@Test
public void shouldGetDirectProxySynthesis() throws URISyntaxException {
ProxySelector proxySelector = mock(ProxySelector.class);
when(proxySelector.select((URI) anyObject())).thenReturn(Arrays.asList(Proxy.NO_PROXY));
- assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector), is("no proxy"));
+ assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("no proxy");
}
@Test
public void shouldGetProxySynthesis() throws URISyntaxException {
ProxySelector proxySelector = mock(ProxySelector.class);
when(proxySelector.select((URI) anyObject())).thenReturn(Arrays.asList((Proxy) new FakeProxy()));
- assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector), is("proxy: http://proxy_url:4040"));
+ assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("proxy: http://proxy_url:4040");
+ }
+
+ @Test
+ public void supported_schemes() {
+ assertThat(new HttpDownloader(new Settings()).getSupportedSchemes()).contains("http");
+ }
+
+ @Test
+ public void uri_description() throws Exception {
+ HttpDownloader downloader = new HttpDownloader(new Settings());
+ String description = downloader.description(new URI("http://sonarsource.org"));
+ assertThat(description).matches("http://sonarsource.org \\(.*\\)");
}
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/UriReaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/UriReaderTest.java
new file mode 100644
index 00000000000..c37a635d568
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/UriReaderTest.java
@@ -0,0 +1,122 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.utils;
+
+import com.google.common.base.Charsets;
+import org.apache.commons.io.IOUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class UriReaderTest {
+
+ private static URI testFile;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void init() throws URISyntaxException {
+ testFile = UriReaderTest.class.getResource("/org/sonar/api/utils/UriReaderTest/foo.txt").toURI();
+ }
+
+ @Test
+ public void file_processor_is_always_available() throws URISyntaxException {
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+
+ assertThat(uriReader.searchForSupportedProcessor(testFile)).isNotNull();
+ }
+
+ @Test
+ public void file_readString() throws Exception {
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ assertThat(uriReader.readString(testFile, Charsets.UTF_8)).isEqualTo("in foo");
+ }
+
+ @Test
+ public void file_readBytes() throws Exception {
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ assertThat(new String(uriReader.readBytes(testFile))).isEqualTo("in foo");
+ }
+
+ @Test
+ public void file_openStream() throws Exception {
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ InputStream input = uriReader.openStream(testFile);
+ assertThat(IOUtils.toString(input)).isEqualTo("in foo");
+ IOUtils.closeQuietly(input);
+ }
+
+ @Test
+ public void file_readString_fails_if_file_not_found() throws Exception {
+ thrown.expect(RuntimeException.class);
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ uriReader.readString(new URI("file:/notfound"), Charsets.UTF_8);
+ }
+
+ @Test
+ public void file_readBytes_fails_if_file_not_found() throws Exception {
+ thrown.expect(RuntimeException.class);
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ uriReader.readBytes(new URI("file:/notfound"));
+ }
+
+ @Test
+ public void file_openStream_fails_if_file_not_found() throws Exception {
+ thrown.expect(RuntimeException.class);
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ uriReader.openStream(new URI("file:/notfound"));
+ }
+
+ @Test
+ public void file_description() {
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+
+ // the prefix file:/ is removed
+ assertThat(uriReader.description(testFile)).doesNotMatch("file:/.*");
+ assertThat(uriReader.description(testFile)).matches(".*foo\\.txt");
+ }
+
+ @Test
+ public void fail_if_unknown_scheme() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[0]);
+ uriReader.readBytes(new URI("ftp://sonarsource.org"));
+ }
+
+ @Test
+ public void register_processors() throws Exception {
+ UriReader.SchemeProcessor processor = mock(UriReader.SchemeProcessor.class);
+ when(processor.getSupportedSchemes()).thenReturn(new String[]{"ftp"});
+ UriReader uriReader = new UriReader(new UriReader.SchemeProcessor[]{processor});
+
+ assertThat(uriReader.searchForSupportedProcessor(new URI("ftp://sonarsource.org"))).isNotNull();
+ }
+}
diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/utils/UriReaderTest/foo.txt b/sonar-plugin-api/src/test/resources/org/sonar/api/utils/UriReaderTest/foo.txt
new file mode 100644
index 00000000000..be36d7b95db
--- /dev/null
+++ b/sonar-plugin-api/src/test/resources/org/sonar/api/utils/UriReaderTest/foo.txt
@@ -0,0 +1 @@
+in foo \ No newline at end of file