diff options
Diffstat (limited to 'sonar-application/src')
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> |