summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java31
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java10
-rw-r--r--sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java4
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml7
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java10
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java228
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java4
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb18
8 files changed, 189 insertions, 123 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java b/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java
index 51d75d53730..199541c12a0 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/local/LocalDatabase.java
@@ -19,9 +19,11 @@
*/
package org.sonar.batch.local;
+import com.google.common.base.Strings;
import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
import org.sonar.api.database.DatabaseProperties;
import org.sonar.api.platform.Server;
@@ -49,14 +51,12 @@ public class LocalDatabase implements BatchComponent {
private final LocalMode localMode;
private final Settings settings;
private final Server server;
- private final HttpDownloader httpDownloader;
private final TempDirectories tempDirectories;
- public LocalDatabase(LocalMode localMode, Settings settings, Server server, HttpDownloader httpDownloader, TempDirectories tempDirectories) {
+ public LocalDatabase(LocalMode localMode, Settings settings, Server server, TempDirectories tempDirectories) {
this.localMode = localMode;
this.settings = settings;
this.server = server;
- this.httpDownloader = httpDownloader;
this.tempDirectories = tempDirectories;
}
@@ -73,14 +73,27 @@ public class LocalDatabase implements BatchComponent {
}
private void downloadDatabase(File toFile) {
+ String login = settings.getString(CoreProperties.LOGIN);
+ String password = settings.getString(CoreProperties.PASSWORD);
+ String resourceKey = settings.getString("sonar.resource");
+ if (null == resourceKey) {
+ throw new SonarException("No resource key was provided using sonar.resource property");
+ }
+
+ URI uri = URI.create(server.getURL() + API_SYNCHRO + "?resource=" + resourceKey);
+
+ HttpDownloader.BaseHttpDownloader downloader = new HttpDownloader.BaseHttpDownloader(settings, null);
+ InputSupplier<InputStream> inputSupplier;
+ if (Strings.isNullOrEmpty(login)) {
+ inputSupplier = downloader.newInputSupplier(uri);
+ } else {
+ inputSupplier = downloader.newInputSupplier(uri, login, password);
+ }
+
try {
- Files.copy(new InputSupplier<InputStream>() {
- public InputStream getInput() {
- return httpDownloader.openStream(URI.create(server.getURL() + API_SYNCHRO));
- }
- }, toFile);
+ Files.copy(inputSupplier, toFile);
} catch (IOException e) {
- throw new SonarException("Unable to download database", e);
+ throw new SonarException("Unable to save local database to file: " + toFile, e);
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java b/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java
index a2e265bd5cd..edebb896eef 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/LocalDatabaseFactory.java
@@ -46,12 +46,12 @@ public class LocalDatabaseFactory implements ServerComponent {
this.serverFileSystem = serverFileSystem;
}
- public byte[] createDatabaseForLocalMode() {
+ public byte[] createDatabaseForLocalMode(int resourceId) {
String name = serverFileSystem.getTempDir().getAbsolutePath() + "db-" + System.nanoTime();
try {
BasicDataSource destination = create(DIALECT, DRIVER, USER, PASSWORD, URL + name);
- copy(database.getDataSource(), destination);
+ copy(database.getDataSource(), destination, resourceId);
close(destination);
return dbFileContent(name);
@@ -60,8 +60,10 @@ public class LocalDatabaseFactory implements ServerComponent {
}
}
- private void copy(DataSource source, DataSource dest) {
- new DbTemplate().copyTable(source, dest, "PROPERTIES", "SELECT * FROM PROPERTIES WHERE (USER_ID IS NULL) AND (RESOURCE_ID IS NULL) AND NOT (PROP_KEY LIKE '%.secured')")
+ private void copy(DataSource source, DataSource dest, int resourceId) {
+ new DbTemplate()
+ .copyTable(source, dest, "PROPERTIES",
+ "SELECT * FROM PROPERTIES WHERE (((USER_ID IS NULL) AND (RESOURCE_ID IS NULL)) OR (RESOURCE_ID='" + resourceId + "')) AND NOT (PROP_KEY LIKE '%.secured')")
.copyTable(source, dest, "RULES_PROFILES", "SELECT * FROM RULES_PROFILES")
.copyTable(source, dest, "RULES", "SELECT * FROM RULES")
.copyTable(source, dest, "RULES_PARAMETERS", "SELECT * FROM RULES_PARAMETERS")
diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java
index 3486fb9638a..3eb0d75c300 100644
--- a/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/persistence/LocalDatabaseFactoryTest.java
@@ -63,10 +63,10 @@ public class LocalDatabaseFactoryTest extends AbstractDaoTestCase {
when(serverFileSystem.getTempDir()).thenReturn(temporaryFolder.getRoot());
- byte[] database = localDatabaseFactory.createDatabaseForLocalMode();
+ byte[] database = localDatabaseFactory.createDatabaseForLocalMode(1);
dataSource = createDatabase(database);
- assertThat(rowCount("PROPERTIES")).isEqualTo(1);
+ assertThat(rowCount("PROPERTIES")).isEqualTo(2);
assertThat(rowCount("PROJECTS")).isZero();
}
diff --git a/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml b/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml
index 281958780db..30343973116 100644
--- a/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml
+++ b/sonar-core/src/test/resources/org/sonar/core/persistence/LocalDatabaseFactoryTest/should_create_database.xml
@@ -1,6 +1,7 @@
<dataset>
<properties id="1" prop_key="resourceProperty" text_value="value1" resource_id="1" user_id="[null]"/>
- <properties id="2" prop_key="globalProperty" text_value="value2" resource_id="[null]" user_id="[null]"/>
- <properties id="3" prop_key="userProperty" text_value="value3" resource_id="[null]" user_id="1"/>
- <properties id="4" prop_key="property.secured" text_value="value4" resource_id="[null]" user_id="[null]"/>
+ <properties id="2" prop_key="resourceProperty" text_value="value2" resource_id="2" user_id="[null]"/>
+ <properties id="3" prop_key="globalProperty" text_value="value3" resource_id="[null]" user_id="[null]"/>
+ <properties id="4" prop_key="userProperty" text_value="value4" resource_id="[null]" user_id="1"/>
+ <properties id="5" prop_key="property.secured" text_value="value5" resource_id="[null]" user_id="[null]"/>
</dataset> \ No newline at end of file
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
index 05e6c192ae8..1e86dd8947f 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
@@ -334,4 +334,14 @@ public interface CoreProperties {
* @since 3.3
*/
String LINKS_SOURCES_DEV = "sonar.links.scm_dev";
+
+ /**
+ * @since 3.4
+ */
+ String LOGIN = "sonar.login";
+
+ /**
+ * @since 3.4
+ */
+ String PASSWORD = "sonar.password";
}
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 7b576266060..0f29541dc30 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
@@ -20,14 +20,15 @@
package org.sonar.api.utils;
import com.google.common.annotations.VisibleForTesting;
-
import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
+import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
@@ -53,75 +54,16 @@ import java.util.List;
* @since 2.2
*/
public class HttpDownloader extends UriReader.SchemeProcessor implements BatchComponent, ServerComponent {
-
public static final int TIMEOUT_MILLISECONDS = 20 * 1000;
- private static final List<String> PROXY_SETTINGS = ImmutableList.of(
- "http.proxyHost", "http.proxyPort", "http.nonProxyHosts",
- "http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort");
- private String userAgent;
+ private final BaseHttpDownloader downloader;
public HttpDownloader(Server server, Settings settings) {
- this(settings, server.getVersion());
+ downloader = new BaseHttpDownloader(settings, server.getVersion());
}
public HttpDownloader(Settings settings) {
- this(settings, null);
- }
-
- private HttpDownloader(Settings settings, String userAgent) {
- initProxy(settings);
- initUserAgent(userAgent);
- }
-
- private void initProxy(Settings settings) {
- propagateProxySystemProperties(settings);
- if (requiresProxyAuthentication(settings)) {
- registerProxyCredentials(settings);
- }
- }
-
- private void initUserAgent(String sonarVersion) {
- userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion));
- System.setProperty("http.agent", userAgent);
- }
-
- public String getProxySynthesis(URI uri) {
- return getProxySynthesis(uri, ProxySelector.getDefault());
- }
-
- @VisibleForTesting
- static String getProxySynthesis(URI uri, ProxySelector proxySelector) {
- List<Proxy> proxies = proxySelector.select(uri);
- if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) {
- return "no proxy";
- }
-
- List<String> descriptions = Lists.newArrayList();
- for (Proxy proxy : proxies) {
- if (proxy.type() != Proxy.Type.DIRECT) {
- descriptions.add("proxy: " + proxy.address());
- }
- }
-
- return Joiner.on(", ").join(descriptions);
- }
-
- private void registerProxyCredentials(Settings settings) {
- Authenticator.setDefault(new ProxyAuthenticator(settings.getString("http.proxyUser"), settings
- .getString("http.proxyPassword")));
- }
-
- private boolean requiresProxyAuthentication(Settings settings) {
- return settings.getString("http.proxyUser") != null;
- }
-
- private void propagateProxySystemProperties(Settings settings) {
- for (String key : PROXY_SETTINGS) {
- if (settings.getString(key) != null) {
- System.setProperty(key, settings.getString(key));
- }
- }
+ downloader = new BaseHttpDownloader(settings, null);
}
@Override
@@ -136,41 +78,45 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo
@Override
byte[] readBytes(URI uri) {
- try {
- return ByteStreams.toByteArray(new HttpInputSupplier(uri));
- } catch (IOException e) {
- throw failToDownload(uri, e);
- }
+ return download(uri);
}
@Override
String readString(URI uri, Charset charset) {
try {
- return CharStreams.toString(CharStreams.newReaderSupplier(new HttpInputSupplier(uri), charset));
+ return CharStreams.toString(CharStreams.newReaderSupplier(downloader.newInputSupplier(uri), charset));
} catch (IOException e) {
throw failToDownload(uri, e);
}
}
+ public String downloadPlainText(URI uri, String encoding) {
+ return readString(uri, Charset.forName(encoding));
+ }
+
public byte[] download(URI uri) {
- return readBytes(uri);
+ try {
+ return ByteStreams.toByteArray(downloader.newInputSupplier(uri));
+ } catch (IOException e) {
+ throw failToDownload(uri, e);
+ }
}
- public String downloadPlainText(URI uri, String encoding) {
- return readString(uri, Charset.forName(encoding));
+ public String getProxySynthesis(URI uri) {
+ return downloader.getProxySynthesis(uri);
}
public InputStream openStream(URI uri) {
try {
- return new HttpInputSupplier(uri).getInput();
- } catch (Exception e) {
- throw new SonarException("Fail to download the file: " + uri + " (" + getProxySynthesis(uri) + ")", e);
+ return downloader.newInputSupplier(uri).getInput();
+ } catch (IOException e) {
+ throw failToDownload(uri, e);
}
}
public void download(URI uri, File toFile) {
try {
- Files.copy(new HttpInputSupplier(uri), toFile);
+ Files.copy(downloader.newInputSupplier(uri), toFile);
} catch (IOException e) {
FileUtils.deleteQuietly(toFile);
throw failToDownload(uri, e);
@@ -178,39 +124,121 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo
}
private SonarException failToDownload(URI uri, IOException e) {
- return new SonarException(String.format("Fail to download the file: %s (%s)", uri, getProxySynthesis(uri)), e);
+ throw new SonarException(String.format("Fail to download: %s (%s)", uri, getProxySynthesis(uri)), e);
}
- class HttpInputSupplier implements InputSupplier<InputStream> {
- private final URI uri;
+ public static class BaseHttpDownloader {
+ private static final List<String> PROXY_SETTINGS = ImmutableList.of(
+ "http.proxyHost", "http.proxyPort", "http.nonProxyHosts",
+ "http.auth.ntlm.domain", "socksProxyHost", "socksProxyPort");
- HttpInputSupplier(URI uri) {
- this.uri = uri;
+ private String userAgent;
+
+ public BaseHttpDownloader(Settings settings, String userAgent) {
+ initProxy(settings);
+ initUserAgent(userAgent);
}
- public InputStream getInput() throws IOException {
- LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri) + ")");
+ private void initProxy(Settings settings) {
+ propagateProxySystemProperties(settings);
+ if (requiresProxyAuthentication(settings)) {
+ registerProxyCredentials(settings);
+ }
+ }
- HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
- connection.setConnectTimeout(TIMEOUT_MILLISECONDS);
- connection.setReadTimeout(TIMEOUT_MILLISECONDS);
- connection.setUseCaches(true);
- connection.setInstanceFollowRedirects(true);
- connection.setRequestProperty("User-Agent", userAgent);
- return connection.getInputStream();
+ private void initUserAgent(String sonarVersion) {
+ userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion));
+ System.setProperty("http.agent", userAgent);
}
- }
-}
-class ProxyAuthenticator extends Authenticator {
- private PasswordAuthentication auth;
+ private String getProxySynthesis(URI uri) {
+ return getProxySynthesis(uri, ProxySelector.getDefault());
+ }
- ProxyAuthenticator(String user, String password) {
- auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray());
- }
+ @VisibleForTesting
+ static String getProxySynthesis(URI uri, ProxySelector proxySelector) {
+ List<Proxy> proxies = proxySelector.select(uri);
+ if (proxies.size() == 1 && proxies.get(0).type().equals(Proxy.Type.DIRECT)) {
+ return "no proxy";
+ }
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return auth;
+ List<String> descriptions = Lists.newArrayList();
+ for (Proxy proxy : proxies) {
+ if (proxy.type() != Proxy.Type.DIRECT) {
+ descriptions.add("proxy: " + proxy.address());
+ }
+ }
+
+ return Joiner.on(", ").join(descriptions);
+ }
+
+ private void registerProxyCredentials(Settings settings) {
+ Authenticator.setDefault(new ProxyAuthenticator(
+ settings.getString("http.proxyUser"),
+ settings.getString("http.proxyPassword")));
+ }
+
+ private boolean requiresProxyAuthentication(Settings settings) {
+ return settings.getString("http.proxyUser") != null;
+ }
+
+ private void propagateProxySystemProperties(Settings settings) {
+ for (String key : PROXY_SETTINGS) {
+ if (settings.getString(key) != null) {
+ System.setProperty(key, settings.getString(key));
+ }
+ }
+ }
+
+ public InputSupplier<InputStream> newInputSupplier(URI uri) {
+ return new HttpInputSupplier(uri, userAgent, null, null);
+ }
+
+ public InputSupplier<InputStream> newInputSupplier(URI uri, String login, String password) {
+ return new HttpInputSupplier(uri, userAgent, login, password);
+ }
+
+ private static class HttpInputSupplier implements InputSupplier<InputStream> {
+ private final String login;
+ private final String password;
+ private final URI uri;
+ private final String userAgent;
+
+ HttpInputSupplier(URI uri, String userAgent, String login, String password) {
+ this.uri = uri;
+ this.userAgent = userAgent;
+ this.login = login;
+ this.password = password;
+ }
+
+ public InputStream getInput() throws IOException {
+ LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri, ProxySelector.getDefault()) + ")");
+
+ HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
+ if (!Strings.isNullOrEmpty(login)) {
+ String encoded = new String(Base64.encodeBase64((login + ":" + password).getBytes()));
+ connection.setRequestProperty("Authorization", "Basic " + encoded);
+ }
+ connection.setConnectTimeout(TIMEOUT_MILLISECONDS);
+ connection.setReadTimeout(TIMEOUT_MILLISECONDS);
+ connection.setUseCaches(true);
+ connection.setInstanceFollowRedirects(true);
+ connection.setRequestProperty("User-Agent", userAgent);
+ return connection.getInputStream();
+ }
+ }
+
+ private static class ProxyAuthenticator extends Authenticator {
+ private final PasswordAuthentication auth;
+
+ ProxyAuthenticator(String user, String password) {
+ auth = new PasswordAuthentication(user, password == null ? new char[0] : password.toCharArray());
+ }
+
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return auth;
+ }
+ }
}
}
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 83101c20fdb..bc626284daa 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
@@ -153,14 +153,14 @@ public class HttpDownloaderTest {
public void shouldGetDirectProxySynthesis() throws URISyntaxException {
ProxySelector proxySelector = mock(ProxySelector.class);
when(proxySelector.select(any(URI.class))).thenReturn(Arrays.asList(Proxy.NO_PROXY));
- assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("no proxy");
+ assertThat(HttpDownloader.BaseHttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("no proxy");
}
@Test
public void shouldGetProxySynthesis() throws URISyntaxException {
ProxySelector proxySelector = mock(ProxySelector.class);
when(proxySelector.select(any(URI.class))).thenReturn(Arrays.<Proxy> asList(new FakeProxy()));
- assertThat(HttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("proxy: http://proxy_url:4040");
+ assertThat(HttpDownloader.BaseHttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("proxy: http://proxy_url:4040");
}
@Test
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb
index c9374031249..c4f7298b66b 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/synchro_controller.rb
@@ -22,12 +22,24 @@ require "json"
class Api::SynchroController < Api::ApiController
- # curl http://localhost:9000/api/synchro -v
+ # curl http://localhost:9000/api/synchro?resource=<resource> -v [-u user:password]
def index
- database_factory = java_facade.getCoreComponentByClassname('org.sonar.core.persistence.LocalDatabaseFactory')
+ require_parameters :resource
+ load_resource()
- dbFileContent = database_factory.createDatabaseForLocalMode()
+ database_factory = java_facade.getCoreComponentByClassname('org.sonar.core.persistence.LocalDatabaseFactory')
+ dbFileContent = database_factory.createDatabaseForLocalMode(@resource.id)
send_data String.from_java_bytes(dbFileContent)
end
+
+ private
+
+ def load_resource
+ resource_id = params[:resource]
+ @resource = Project.by_key(resource_id)
+ return not_found("Resource [#{resource_id}] not found") if @resource.nil?
+ return access_denied unless is_user?(@resource)
+ end
end
+