aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-application/src
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-application/src')
-rw-r--r--sonar-application/src/main/assembly/conf/sonar.properties4
-rw-r--r--sonar-application/src/main/assembly/conf/wrapper.conf8
-rw-r--r--sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java8
-rw-r--r--sonar-application/src/main/java/org/sonar/application/ForkProcesses.java104
-rw-r--r--sonar-application/src/main/java/org/sonar/application/Installation.java161
-rw-r--r--sonar-application/src/main/java/org/sonar/application/Webapp.java1
-rw-r--r--sonar-application/src/main/resources/logback.xml12
7 files changed, 290 insertions, 8 deletions
diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties
index 0ff37108e4a..b8b255f94bb 100644
--- a/sonar-application/src/main/assembly/conf/sonar.properties
+++ b/sonar-application/src/main/assembly/conf/sonar.properties
@@ -10,8 +10,8 @@
#--------------------------------------------------------------------------------------------------
# ELASTICSEARCH
-sonar.es.java_opts="-Xmx1G -Xms1G"
-sonar.web.java_opts="-Xmx128m -Xms128m"
+sonar.es.javaOpts=-Xmx256m -Xms256m
+sonar.web.java_opts=-Xmx76m
#--------------------------------------------------------------------------------------------------
diff --git a/sonar-application/src/main/assembly/conf/wrapper.conf b/sonar-application/src/main/assembly/conf/wrapper.conf
index 19be89188ed..4fd1f4d9363 100644
--- a/sonar-application/src/main/assembly/conf/wrapper.conf
+++ b/sonar-application/src/main/assembly/conf/wrapper.conf
@@ -1,19 +1,19 @@
# Java Additional Parameters
wrapper.java.additional.1=-Djava.awt.headless=true
-wrapper.java.additional.2=-XX:MaxPermSize=160m
+#wrapper.java.additional.2=-XX:MaxPermSize=160m
wrapper.java.additional.3=-XX:+HeapDumpOnOutOfMemoryError
wrapper.java.additional.4=-Dfile.encoding=UTF-8
wrapper.java.additional.5=-Djruby.management.enabled=false
# Maximum amount of memory of Java VM
-wrapper.java.additional.6=-Xmx1024M
+wrapper.java.additional.2=-Xmx32M
# RECOMMENDED : uncomment if Java Virtual Machine is a JDK but not a JRE. To know which JVM you use, execute
# 'java -version'. JDK displays 'Server VM'.
#wrapper.java.additional.7=-server
# Initial JVM heap size (in MB)
-wrapper.java.initmemory=256
+wrapper.java.initmemory=16
#********************************************************************
# Wrapper Java Properties
@@ -42,7 +42,7 @@ wrapper.java.classpath.6=../../extensions/jdbc-driver/mssql/*.jar
wrapper.java.library.path.1=./lib
# Application parameters. Add parameters as needed starting from 1
-wrapper.app.parameter.1=org.sonar.application.StartServer
+wrapper.app.parameter.1=org.sonar.application.ForkProcesses
# Do not touch the following property. Max memory is set with -Xmx (see above).
# See https://jira.codehaus.org/browse/SONAR-5204
diff --git a/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java
index a677f8bcf11..ceca36c6718 100644
--- a/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java
+++ b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java
@@ -34,7 +34,7 @@ class EmbeddedTomcat {
private final Env env;
private Tomcat tomcat = null;
private Thread hook = null;
- private boolean stopping = false;
+ private boolean stopping = false, ready = false;
EmbeddedTomcat(Env env) {
this.env = env;
@@ -71,6 +71,7 @@ class EmbeddedTomcat {
Webapp.configure(tomcat, env, props);
tomcat.start();
addShutdownHook();
+ ready = true;
tomcat.getServer().await();
// Shutdown command received
@@ -102,6 +103,7 @@ class EmbeddedTomcat {
}
tomcat = null;
stopping = false;
+ ready = false;
File tempDir = env.file(TEMP_RELATIVE_PATH);
FileUtils.deleteQuietly(tempDir);
@@ -117,6 +119,10 @@ class EmbeddedTomcat {
}
}
+ boolean isReady( ){
+ return ready;
+ }
+
int port() {
Connector[] connectors = tomcat.getService().findConnectors();
if (connectors.length > 0) {
diff --git a/sonar-application/src/main/java/org/sonar/application/ForkProcesses.java b/sonar-application/src/main/java/org/sonar/application/ForkProcesses.java
new file mode 100644
index 00000000000..bc6339d3f48
--- /dev/null
+++ b/sonar-application/src/main/java/org/sonar/application/ForkProcesses.java
@@ -0,0 +1,104 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.application;
+
+import org.sonar.process.Monitor;
+import org.sonar.process.NetworkUtils;
+import org.sonar.process.ProcessWrapper;
+
+import javax.annotation.Nullable;
+
+public class ForkProcesses {
+ private Monitor monitor;
+ private final Thread shutdownHook;
+ private ProcessWrapper elasticsearch;
+ private ProcessWrapper server;
+
+ public ForkProcesses() throws Exception {
+ Installation installation = new Installation();
+
+ String esPort = installation.prop("sonar.es.node.port", null);
+ if (esPort == null) {
+ esPort = String.valueOf(NetworkUtils.freePort());
+ installation.setProp("sonar.es.node.port", esPort);
+ }
+ installation.setProp("sonar.es.type", "TRANSPORT");
+
+ shutdownHook = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ monitor.interrupt();
+ terminateAndWait(elasticsearch);
+ terminateAndWait(server);
+ }
+ });
+
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+ elasticsearch = new ProcessWrapper(
+ installation.homeDir().getAbsolutePath(),
+ installation.prop("sonar.es.javaOpts", "-server -Xmx256m -Xms128m -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly"),
+ "org.sonar.search.ElasticSearch",
+ installation.props(),
+ "ES",
+ installation.starPath("lib/search"));
+
+
+ server = new ProcessWrapper(
+ installation.homeDir().getAbsolutePath(),
+ installation.prop("sonar.web.javaOpts", "-Xmx768m -server -XX:MaxPermSize=160m -Djava.awt.headless=true -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -Djruby.management.enabled=false"),
+ "org.sonar.server.app.ServerProcess",
+ installation.props(),
+ "SQ",
+ installation.starPath("lib"));
+
+ monitor = new Monitor();
+ monitor.registerProcess(elasticsearch);
+ monitor.registerProcess(server);
+ monitor.start();
+ try {
+ monitor.join();
+ } catch (InterruptedException e) {
+ stop(true);
+ }
+ stop(true);
+ }
+
+ public void stop(boolean waitForCompletion) {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ shutdownHook.start();
+ if (waitForCompletion) {
+ try {
+ shutdownHook.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ private void terminateAndWait(@Nullable ProcessWrapper process) {
+ if (process != null && process.getThread() != null) {
+ process.terminate();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ForkProcesses();
+ }
+}
diff --git a/sonar-application/src/main/java/org/sonar/application/Installation.java b/sonar-application/src/main/java/org/sonar/application/Installation.java
new file mode 100644
index 00000000000..41b87b60b15
--- /dev/null
+++ b/sonar-application/src/main/java/org/sonar/application/Installation.java
@@ -0,0 +1,161 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.application;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class Installation {
+
+ // guessed from location of sonar-application.jar
+ private final File homeDir;
+ private final File tempDir, dataDir, logsDir, webDir;
+ private final Map<String, String> props = new HashMap<String, String>();
+
+ Installation() throws URISyntaxException, IOException {
+ // TODO make it configurable with sonar.path.home ?
+ // lib/sonar-application.jar
+ File appJar = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
+ homeDir = appJar.getParentFile().getParentFile();
+
+ Properties p = new Properties();
+ File propsFile = new File(homeDir, "conf/sonar.properties");
+ if (propsFile.exists()) {
+ FileReader reader = new FileReader(propsFile);
+ try {
+ p.load(reader);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+ p.putAll(System.getenv());
+ p.putAll(System.getProperties());
+ p = ConfigurationUtils.interpolateEnvVariables(p);
+ for (Map.Entry<Object, Object> entry : p.entrySet()) {
+ Object val = entry.getValue();
+ if (val != null) {
+ this.props.put(entry.getKey().toString(), val.toString());
+ }
+ }
+
+ props.put("sonar.path.home", homeDir.getAbsolutePath());
+ this.dataDir = existingDir("sonar.path.data", "data");
+ this.tempDir = freshDir("sonar.path.temp", "temp");
+ this.logsDir = existingDir("sonar.path.logs", "logs");
+ this.webDir = existingDir("sonar.path.web", "web");
+ }
+
+ File homeDir() {
+ return homeDir;
+ }
+
+ File esDir() {
+ return new File(homeDir, "data/es");
+ }
+
+ File webDir() {
+ return webDir;
+ }
+
+ File tempDir() {
+ return tempDir;
+ }
+
+ String starPath(String relativePath) {
+ File dir = new File(homeDir, relativePath);
+ return FilenameUtils.concat(dir.getAbsolutePath(), "*");
+ }
+
+ private File freshDir(String propKey, String defaultRelativePath) throws IOException {
+ File dir = configuredDir(propKey, defaultRelativePath);
+ FileUtils.deleteQuietly(dir);
+ FileUtils.forceMkdir(dir);
+ return dir;
+ }
+
+ private File existingDir(String propKey, String defaultRelativePath) throws IOException {
+ File dir = configuredDir(propKey, defaultRelativePath);
+ if (!dir.exists()) {
+ // TODO replace by MessageException
+ throw new IllegalStateException(String.format("Directory does not exist: %s. Please check property %s", dir.getAbsolutePath(), propKey));
+ }
+ if (!dir.isDirectory()) {
+ // TODO replace by MessageException
+ throw new IllegalStateException(String.format("Not a directory: %s. Please check property %s", dir.getAbsolutePath(), propKey));
+ }
+ return dir;
+ }
+
+ private File configuredDir(String propKey, String defaultRelativePath) {
+ String path = prop(propKey, defaultRelativePath);
+ File d = new File(path);
+ if (!d.isAbsolute()) {
+ d = new File(homeDir, path);
+ }
+ props.put(propKey, d.getAbsolutePath());
+ return d;
+ }
+
+ Map<String, String> props() {
+ return props;
+ }
+
+ @CheckForNull
+ String prop(String key, @Nullable String defaultValue) {
+ String s = props.get(key);
+ return s != null ? s : defaultValue;
+ }
+
+ @CheckForNull
+ Integer propAsInt(String key) {
+ String s = prop(key, null);
+ if (s != null && !"".equals(s)) {
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException(String.format("Value of property %s is not an integer: %s", key, s), e);
+ }
+ }
+ return null;
+ }
+
+ void setProp(String key, String value) {
+ props.put(key, value);
+ }
+
+ void logInfo(String message) {
+ System.out.println(message);
+ }
+
+ void logError(String message) {
+ System.err.println(message);
+ }
+}
diff --git a/sonar-application/src/main/java/org/sonar/application/Webapp.java b/sonar-application/src/main/java/org/sonar/application/Webapp.java
index 8d5f5a4590a..082ebdecdea 100644
--- a/sonar-application/src/main/java/org/sonar/application/Webapp.java
+++ b/sonar-application/src/main/java/org/sonar/application/Webapp.java
@@ -37,6 +37,7 @@ class Webapp {
context.setConfigFile(env.file("web/META-INF/context.xml").toURI().toURL());
context.addParameter(PROPERTY_LOG_PROFILING_LEVEL, props.of(PROPERTY_LOG_PROFILING_LEVEL, "NONE"));
context.addParameter(PROPERTY_LOG_CONSOLE, props.of(PROPERTY_LOG_CONSOLE, "false"));
+
configureRailsMode(props, context);
context.setJarScanner(new NullJarScanner());
diff --git a/sonar-application/src/main/resources/logback.xml b/sonar-application/src/main/resources/logback.xml
index 259b15ff591..067d353bdd5 100644
--- a/sonar-application/src/main/resources/logback.xml
+++ b/sonar-application/src/main/resources/logback.xml
@@ -40,9 +40,19 @@
<appender-ref ref="CONSOLE"/>
</logger>
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>
+ %d{yyyy.MM.dd HH:mm:ss} %-5level %msg%n
+ </pattern>
+ </encoder>
+ </appender>
+
<root>
- <level value="INFO"/>
+ <level value="DEBUG"/>
+ <appender-ref ref="CONSOLE"/>
<appender-ref ref="LOGFILE"/>
</root>
+
</configuration>