001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.batch.bootstrap;
021
022 import com.google.common.base.Throwables;
023 import org.apache.commons.io.FileUtils;
024 import org.apache.commons.lang.StringUtils;
025 import org.slf4j.Logger;
026 import org.slf4j.LoggerFactory;
027 import org.sonar.api.BatchComponent;
028 import org.sonar.api.CoreProperties;
029 import org.sonar.api.config.Settings;
030 import org.sonar.api.database.DatabaseProperties;
031 import org.sonar.api.utils.HttpDownloader.HttpException;
032 import org.sonar.api.utils.SonarException;
033 import org.sonar.api.utils.TempFolder;
034
035 import java.io.File;
036 import java.net.SocketTimeoutException;
037
038 /**
039 * @since 3.4
040 */
041 public class PreviewDatabase implements BatchComponent {
042 private static final Logger LOG = LoggerFactory.getLogger(PreviewDatabase.class);
043
044 private static final String DIALECT = "h2";
045 private static final String DRIVER = "org.h2.Driver";
046 private static final String URL = "jdbc:h2:";
047 private static final String USER = "sonar";
048 private static final String PASSWORD = USER;
049
050 private final Settings settings;
051 private final ServerClient server;
052 private final TempFolder tempUtils;
053 private final AnalysisMode mode;
054
055 public PreviewDatabase(Settings settings, ServerClient server, TempFolder tempUtils, AnalysisMode mode) {
056 this.settings = settings;
057 this.server = server;
058 this.tempUtils = tempUtils;
059 this.mode = mode;
060 }
061
062 public void start() {
063 if (mode.isPreview()) {
064 File databaseFile = tempUtils.newFile("preview", ".h2.db");
065
066 int readTimeoutSec = mode.getPreviewReadTimeoutSec();
067 downloadDatabase(databaseFile, readTimeoutSec * 1000);
068
069 String databasePath = StringUtils.removeEnd(databaseFile.getAbsolutePath(), ".h2.db");
070 replaceSettings(databasePath);
071 }
072 }
073
074 private void downloadDatabase(File toFile, int readTimeoutMillis) {
075 String projectKey = null;
076 try {
077 projectKey = settings.getString(CoreProperties.PROJECT_KEY_PROPERTY);
078 String branch = settings.getString(CoreProperties.PROJECT_BRANCH_PROPERTY);
079 if (StringUtils.isNotBlank(branch)) {
080 projectKey = String.format("%s:%s", projectKey, branch);
081 }
082 if (StringUtils.isBlank(projectKey)) {
083 server.download("/batch_bootstrap/db", toFile, readTimeoutMillis);
084 } else {
085 server.download("/batch_bootstrap/db?project=" + projectKey, toFile, readTimeoutMillis);
086 }
087 LOG.debug("Dry Run database size: {}", FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(toFile)));
088 } catch (SonarException e) {
089 handleException(readTimeoutMillis, projectKey, e);
090 throw e;
091 }
092 }
093
094 private void handleException(int readTimeout, String projectKey, SonarException e) {
095 Throwable rootCause = Throwables.getRootCause(e);
096 if (rootCause instanceof SocketTimeoutException) {
097 // Pico will unwrap the first runtime exception
098 throw new SonarException(new SonarException(String.format("Preview database read timed out after %s ms. You can try to increase read timeout with property -D"
099 + CoreProperties.PREVIEW_READ_TIMEOUT_SEC + " (in seconds)",
100 readTimeout), e));
101 }
102 if (projectKey != null && (rootCause instanceof HttpException) && (((HttpException) rootCause).getResponseCode() == 401)) {
103 // Pico will unwrap the first runtime exception
104 throw new SonarException(new SonarException(String.format("You don't have access rights to project [%s]", projectKey), e));
105 }
106 }
107
108 private void replaceSettings(String databasePath) {
109 settings
110 .setProperty(DatabaseProperties.PROP_DIALECT, DIALECT)
111 .setProperty(DatabaseProperties.PROP_DRIVER, DRIVER)
112 .setProperty(DatabaseProperties.PROP_USER, USER)
113 .setProperty(DatabaseProperties.PROP_PASSWORD, PASSWORD)
114 .setProperty(DatabaseProperties.PROP_URL, URL + databasePath);
115 }
116 }