diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2013-10-01 16:51:37 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2013-10-01 16:51:57 +0200 |
commit | af19a257160eae52f2f5a08cfb979625a9cf5cff (patch) | |
tree | 3aa8ecd06fd0f57619c98b4bbc133dab8b96aeef | |
parent | 3a9dfb1fd7e4c854da5eab3d041e70b27e9c709c (diff) | |
download | sonarqube-af19a257160eae52f2f5a08cfb979625a9cf5cff.tar.gz sonarqube-af19a257160eae52f2f5a08cfb979625a9cf5cff.zip |
SONAR-4675 Replace Jetty web server by Tomcat 7
50 files changed, 1351 insertions, 1307 deletions
diff --git a/plugins/sonar-core-plugin/pom.xml b/plugins/sonar-core-plugin/pom.xml index e60b525073b..62e52bb27b5 100644 --- a/plugins/sonar-core-plugin/pom.xml +++ b/plugins/sonar-core-plugin/pom.xml @@ -14,6 +14,11 @@ <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-plugin-api</artifactId> <scope>provided</scope> diff --git a/plugins/sonar-cpd-plugin/pom.xml b/plugins/sonar-cpd-plugin/pom.xml index 515bac9c499..aa0cc61f45f 100644 --- a/plugins/sonar-cpd-plugin/pom.xml +++ b/plugins/sonar-cpd-plugin/pom.xml @@ -21,6 +21,11 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> <dependency> <groupId>org.codehaus.sonar</groupId> diff --git a/plugins/sonar-dbcleaner-plugin/pom.xml b/plugins/sonar-dbcleaner-plugin/pom.xml index 5a8aa31481e..18525c8a320 100644 --- a/plugins/sonar-dbcleaner-plugin/pom.xml +++ b/plugins/sonar-dbcleaner-plugin/pom.xml @@ -16,6 +16,11 @@ <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-plugin-api</artifactId> <scope>provided</scope> diff --git a/plugins/sonar-maven-batch-plugin/pom.xml b/plugins/sonar-maven-batch-plugin/pom.xml index c2406654a14..ac25b80072a 100644 --- a/plugins/sonar-maven-batch-plugin/pom.xml +++ b/plugins/sonar-maven-batch-plugin/pom.xml @@ -19,6 +19,11 @@ <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-batch</artifactId> <version>${project.version}</version> @@ -7,7 +7,7 @@ <packaging>pom</packaging> <version>4.0-SNAPSHOT</version> <name>SonarQube</name> - <url>http://www.sonarsource.org/</url> + <url>http://www.sonarqube.org/</url> <description>Open source platform for continuous inspection of code quality</description> <modules> @@ -76,6 +76,9 @@ <sonarGwt.version>3.3.1</sonarGwt.version> <h2.version>1.3.172</h2.version> <jetty.version>8.1.12.v20130726</jetty.version> + <logback.version>1.0.13</logback.version> + <slf4j.version>1.7.5</slf4j.version> + <tomcat.version>7.0.42</tomcat.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.min.version>3.0.5</maven.min.version> <maven.api.version>2.2.0</maven.api.version> @@ -658,6 +661,12 @@ <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>10.0.1</version> + <exclusions> + <exclusion> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>com.google.code.findbugs</groupId> @@ -788,27 +797,37 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.6.2</version> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jul-to-slf4j</artifactId> + <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> - <version>1.6.2</version> + <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> - <version>1.6.2</version> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-access</artifactId> + <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> - <version>0.9.30</version> + <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> - <version>0.9.30</version> + <version>${logback.version}</version> </dependency> <dependency> <groupId>com.h2database</groupId> @@ -920,6 +939,14 @@ <groupId>classworlds</groupId> <artifactId>classworlds</artifactId> </exclusion> + <exclusion> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </exclusion> + <exclusion> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + </exclusion> </exclusions> </dependency> <dependency> @@ -959,9 +986,9 @@ <version>3.0.1</version> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> - <version>3.0.20100224</version> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.0.1</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> @@ -969,21 +996,6 @@ <version>${jetty.version}</version> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlets</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> <groupId>org.skyscreamer</groupId> <artifactId>jsonassert</artifactId> <version>1.2.0</version> @@ -1065,6 +1077,35 @@ <artifactId>sonar-runner-api</artifactId> <version>2.3</version> </dependency> + + <!-- tomcat --> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>${tomcat.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-jasper</artifactId> + <version>${tomcat.version}</version> + <exclusions> + <exclusion> + <groupId>org.eclipse.jdt.core.compiler</groupId> + <artifactId>ecj</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + <version>${tomcat.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + <version>${tomcat.version}</version> + </dependency> + </dependencies> </dependencyManagement> diff --git a/sonar-application/pom.xml b/sonar-application/pom.xml index 5a9e17e4cd8..66290c24389 100644 --- a/sonar-application/pom.xml +++ b/sonar-application/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -16,37 +17,62 @@ <dependencies> <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-server</artifactId> - <version>${project.version}</version> - <type>war</type> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> </dependency> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> </dependency> <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> + <groupId>org.slf4j</groupId> + <artifactId>jul-to-slf4j</artifactId> </dependency> <dependency> - <groupId>commons-lang</groupId> - <artifactId>commons-lang</artifactId> - <scope>test</scope> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-access</artifactId> </dependency> <dependency> - <groupId>org.codehaus.sonar</groupId> - <artifactId>sonar-testing-harness</artifactId> - <scope>test</scope> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> - <scope>test</scope> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + </dependency> + <dependency> + <!-- TODO remove this unused dependency, but how to disable Jasper in embedded tomcat ? --> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-jasper</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + </dependency> + <!-- + TODO + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-dbcp</artifactId> + <version>${tomcat.version}</version> + </dependency> + --> + + + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-server</artifactId> + <version>${project.version}</version> + <type>war</type> </dependency> <dependency> <groupId>mysql</groupId> @@ -161,7 +187,6 @@ <type>sonar-plugin</type> <scope>runtime</scope> </dependency> - <dependency> <groupId>org.sonatype.jsw-binaries</groupId> <artifactId>jsw-binaries</artifactId> @@ -170,11 +195,34 @@ <scope>provided</scope> </dependency> <dependency> + <!-- do not upgrade because of licensing change --> <groupId>tanukisoft</groupId> <artifactId>wrapper</artifactId> <version>3.2.3</version> <scope>runtime</scope> </dependency> + + <!-- unit tests --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.easytesting</groupId> + <artifactId>fest-assert</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.github.kevinsawicki</groupId> + <artifactId>http-request</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -204,8 +252,8 @@ <phase>package</phase> <configuration> <target> - <checksum file="${project.build.directory}/sonar-${project.version}.zip" algorithm="md5" /> - <checksum file="${project.build.directory}/sonar-${project.version}.zip" algorithm="sha" /> + <checksum file="${project.build.directory}/sonar-${project.version}.zip" algorithm="md5"/> + <checksum file="${project.build.directory}/sonar-${project.version}.zip" algorithm="sha"/> </target> </configuration> <goals> diff --git a/sonar-application/src/main/assembly/conf/logback-access.xml b/sonar-application/src/main/assembly/conf/logback-access.xml new file mode 100644 index 00000000000..8e2f63b3cd9 --- /dev/null +++ b/sonar-application/src/main/assembly/conf/logback-access.xml @@ -0,0 +1,25 @@ +<!-- + + See http://logback.qos.ch/access.html#configuration + +--> +<configuration debug="false"> + <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> + + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${SONAR_HOME}/logs/access.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <param name="FileNamePattern" value="${SONAR_HOME}/logs/access.%i.log"/> + <param name="MinIndex" value="1"/> + <param name="MaxIndex" value="3"/> + </rollingPolicy> + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <param name="MaxFileSize" value="5MB"/> + </triggeringPolicy> + <encoder> + <pattern>combined</pattern> + </encoder> + </appender> + + <appender-ref ref="FILE" /> +</configuration> diff --git a/sonar-application/src/main/assembly/conf/logback.xml b/sonar-application/src/main/assembly/conf/logback.xml index 5859163242d..570c7169247 100644 --- a/sonar-application/src/main/assembly/conf/logback.xml +++ b/sonar-application/src/main/assembly/conf/logback.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <configuration debug="false"> + <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> <appender name="SONAR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${SONAR_HOME}/logs/sonar.log</File> @@ -13,24 +14,7 @@ <param name="MaxFileSize" value="5MB"/> </triggeringPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> - <pattern> - %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n - </pattern> - </encoder> - </appender> - - <!-- appender used to profile Sonar Server --> - <appender name="PROFILING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> - <File>${SONAR_HOME}/logs/profiling.log</File> - <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> - <param name="FileNamePattern" value="${SONAR_HOME}/logs/profiling.%i.log"/> - <param name="MinIndex" value="1"/> - <param name="MaxIndex" value="3"/> - </rollingPolicy> - <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> - <param name="MaxFileSize" value="5MB"/> - </triggeringPolicy> - <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> + <!-- Use %d{yyyy.MM.dd HH:mm:ss.SSS} to display milliseconds --> <pattern> %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n </pattern> @@ -47,11 +31,10 @@ <logger name="rails" additivity="false"> <level value="DEBUG"/> - <appender-ref ref="PROFILING_FILE"/> </logger> Example of command-line to get the HTTP requests with execution time greater than 10s : - grep 'rails Completed in [0-9]\{5,\}ms' < profiling.log + grep 'rails Completed in [0-9]\{5,\}ms' < sonar.log --> <logger name="org.hibernate.cache.ReadWriteCache"> @@ -96,4 +79,4 @@ <appender-ref ref="SONAR_FILE"/> </root> -</configuration>
\ No newline at end of file +</configuration> diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties index 28ce4528bbb..3b4fc79cd0e 100644 --- a/sonar-application/src/main/assembly/conf/sonar.properties +++ b/sonar-application/src/main/assembly/conf/sonar.properties @@ -1,4 +1,3 @@ -#-------------------------------------------------------- # This file must contain only ISO 8859-1 characters # see http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Properties.html#load(java.io.InputStream) # @@ -8,34 +7,45 @@ # # # See also the file conf/wrapper.conf for JVM advanced settings -#--------------------------------------------------------- -#--------------------------------------------------------- -# WEB SETTINGS - STANDALONE MODE ONLY -# These settings are ignored when the war file is deployed to a JEE server. -#--------------------------------------------------------- -# Listen host/port and context path (for example / or /sonar). Default values are 0.0.0.0:9000/. + +#-------------------------------------------------------------------------------------------------- +# WEB SERVER + +# Binding address #sonar.web.host=0.0.0.0 + +# TCP port for incoming HTTP connections #sonar.web.port=9000 + +# Web context must start with slash (/) #sonar.web.context=/ -# Log HTTP requests. Deactivated by default. -#sonar.web.jettyRequestLogs= ../../logs/jetty-yyyy_mm_dd.request.log -#sonar.web.jetty.threads.min=5 -#sonar.web.jetty.threads.max=50 +# The maximum number of connections that the server will accept and process at any given time. +# When this number has been reached, the server will not accept any more connections until +# the number of connections falls below this value. The operating system may still accept connections +# based on the sonar.web.connections.acceptCount property. The default value is 50. +#sonar.web.connections.maxThreads=50 + +# The minimum number of threads always kept running. If not specified, the default of 5 is used. +#sonar.web.connections.minThreads=5 + +# The maximum queue length for incoming connection requests when all possible request processing +# threads are in use. Any requests received when the queue is full will be refused. +# The default value is 25. +#sonar.web.connections.acceptCount=25 -#----------------------------------------------------------------------- + + +#-------------------------------------------------------------------------------------------------- # DATABASE # -# IMPORTANT: the embedded database H2 is used by default. -# It is recommended for tests only. Please use an external database -# for production environment (MySQL, Oracle, Postgresql, SQLServer) -# -#----------------------------------------------------------------------- +# IMPORTANT: the embedded H2 database is used by default. It is recommended for tests only. +# Please use a production-ready database. Supported databases are MySQL, Oracle, PostgreSQL +# and Microsoft SQLServer. -#----- Credentials -# Permissions to create tables and indexes must be granted to JDBC user. +# Permissions to create tables, indices and triggers must be granted to JDBC user. # The schema must be created first. sonar.jdbc.username=sonar sonar.jdbc.password=sonar @@ -100,12 +110,12 @@ sonar.jdbc.minEvictableIdleTimeMillis=600000 sonar.jdbc.timeBetweenEvictionRunsMillis=30000 -#--------------------------------------------------------- + +#-------------------------------------------------------------------------------------------------- # UPDATE CENTER -#--------------------------------------------------------- # The Update Center requires an internet connection to request http://update.sonarsource.org -# It is activated by default: +# It is enabled by default. #sonar.updatecenter.activate=true # HTTP proxy (default none) @@ -123,9 +133,10 @@ sonar.jdbc.timeBetweenEvictionRunsMillis=30000 #http.proxyUser= #http.proxyPassword= -#--------------------------------------------------------- + + +#-------------------------------------------------------------------------------------------------- # NOTIFICATIONS -#--------------------------------------------------------- # Delay (in seconds) between processing of notification queue sonar.notifications.delay=60 diff --git a/sonar-application/src/main/assembly/conf/wrapper.conf b/sonar-application/src/main/assembly/conf/wrapper.conf index 30f68945ede..b12d3701bc7 100644 --- a/sonar-application/src/main/assembly/conf/wrapper.conf +++ b/sonar-application/src/main/assembly/conf/wrapper.conf @@ -32,7 +32,7 @@ wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp # Java Classpath (include wrapper.jar) Add class path elements as # needed starting from 1 wrapper.java.classpath.1=../../lib/*.jar -wrapper.java.classpath.2=../../ +wrapper.java.classpath.2=../../conf wrapper.java.classpath.3=../../extensions/jdbc-driver/mysql/*.jar wrapper.java.classpath.4=../../extensions/jdbc-driver/oracle/*.jar wrapper.java.classpath.5=../../extensions/jdbc-driver/postgresql/*.jar @@ -70,7 +70,7 @@ wrapper.console.loglevel=INFO wrapper.logfile=../../logs/sonar.log # Format of output for the log file. (See docs for formats) -wrapper.logfile.format=LPTM +wrapper.logfile.format=TLM # Log Level for log file output. (See docs for log levels) wrapper.logfile.loglevel=INFO diff --git a/sonar-application/src/main/java/org/sonar/application/Connectors.java b/sonar-application/src/main/java/org/sonar/application/Connectors.java new file mode 100644 index 00000000000..f6c8965d166 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Connectors.java @@ -0,0 +1,69 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; + +class Connectors { + + static final String PROPERTY_SHUTDOWN_TOKEN = "sonar.web.shutdown.token"; + static final String PROPERTY_SHUTDOWN_PORT = "sonar.web.shutdown.port"; + static final String PROPERTY_MIN_THREADS = "sonar.web.connections.minThreads"; + static final String PROPERTY_MAX_THREADS = "sonar.web.connections.maxThreads"; + static final String PROPERTY_ACCEPT_COUNT = "sonar.web.connections.acceptCount"; + + static void configure(Tomcat tomcat, Props props) { + tomcat.getServer().setAddress(props.of("sonar.web.host", "0.0.0.0")); + configureShutdown(tomcat, props); + + Connector connector = new Connector("HTTP/1.1"); + + // TODO manage redirects from other ports ? + + connector.setPort(props.intOf("sonar.web.port", 9000)); + configurePool(props, connector); + configureCompression(connector); + tomcat.setConnector(connector); + tomcat.getService().addConnector(connector); + } + + private static void configureShutdown(Tomcat tomcat, Props props) { + String shutdownToken = props.of(PROPERTY_SHUTDOWN_TOKEN); + Integer shutdownPort = props.intOf(PROPERTY_SHUTDOWN_PORT); + if (shutdownToken != null && !"".equals(shutdownToken) && shutdownPort != null) { + tomcat.getServer().setPort(shutdownPort); + tomcat.getServer().setShutdown(shutdownToken); + } + } + + private static void configurePool(Props props, Connector connector) { + connector.setProperty("acceptorThreadCount", String.valueOf(2)); + connector.setProperty("minSpareThreads", String.valueOf(props.intOf(PROPERTY_MIN_THREADS, 5))); + connector.setProperty("maxThreads", String.valueOf(props.intOf(PROPERTY_MAX_THREADS, 50))); + connector.setProperty("acceptCount", String.valueOf(props.intOf(PROPERTY_ACCEPT_COUNT, 25))); + } + + private static void configureCompression(Connector connector) { + connector.setProperty("compression", "on"); + connector.setProperty("compressionMinSize", "1024"); + connector.setProperty("compressableMimeType", "text/html,text/xml,text/plain,text/css,application/json,application/javascript"); + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java new file mode 100644 index 00000000000..79d9cef2a56 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/EmbeddedTomcat.java @@ -0,0 +1,112 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.apache.commons.io.FileUtils; + +import java.io.File; + +class EmbeddedTomcat { + + public static final String TEMP_RELATIVE_PATH = "temp/tomcat"; + + private final Env env; + private Tomcat tomcat = null; + private Thread hook = null; + private boolean stopping = false; + + EmbeddedTomcat(Env env) { + this.env = env; + } + + void start() throws Exception { + if (tomcat != null || hook != null) { + throw new IllegalStateException("Tomcat is already started"); + } + + tomcat = new Tomcat(); + + // Initialize directories + String basedir = env.freshDir(TEMP_RELATIVE_PATH).getCanonicalPath(); + tomcat.setBaseDir(basedir); + tomcat.getHost().setAppBase(basedir); + tomcat.getHost().setAutoDeploy(false); + tomcat.getHost().setCreateDirs(false); + tomcat.getHost().setDeployOnStartup(true); + + Props props = Props.create(env); + Logging.configure(tomcat, env); + Connectors.configure(tomcat, props); + Webapp.configure(tomcat, env, props); + + tomcat.start(); + addShutdownHook(); + tomcat.getServer().await(); + + // Shutdown command received + stop(); + } + + private void addShutdownHook() { + hook = new Thread() { + @Override + public void run() { + EmbeddedTomcat.this.doStop(); + } + }; + Runtime.getRuntime().addShutdownHook(hook); + } + + + void stop() { + removeShutdownHook(); + doStop(); + } + + private synchronized void doStop() { + try { + if (tomcat != null && !stopping) { + stopping = true; + tomcat.stop(); + tomcat.destroy(); + } + tomcat = null; + stopping = false; + File tempDir = env.file(TEMP_RELATIVE_PATH); + FileUtils.deleteQuietly(tempDir); + + } catch (LifecycleException e) { + throw new IllegalStateException("Fail to stop web server", e); + } + } + + private void removeShutdownHook() { + if (hook != null && !hook.isAlive()) { + Runtime.getRuntime().removeShutdownHook(hook); + hook = null; + } + } + + int port() { + return tomcat.getService().findConnectors()[0].getLocalPort(); + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/Env.java b/sonar-application/src/main/java/org/sonar/application/Env.java new file mode 100644 index 00000000000..53f25a9b8d7 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Env.java @@ -0,0 +1,69 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +class Env { + + private final File confFile; + + Env(File confFile) { + this.confFile = confFile; + } + + Env() throws URISyntaxException { + this(new File(Env.class.getResource("/sonar.properties").toURI())); + } + + File rootDir() { + return confFile.getParentFile().getParentFile(); + } + + File file(String relativePath) { + return new File(rootDir(), relativePath); + } + + File freshDir(String relativePath) { + File dir = new File(rootDir(), relativePath); + FileUtils.deleteQuietly(dir); + dir.mkdirs(); + return dir; + } + + /** + * This check is required in order to provide more meaningful message than JRuby - see SONAR-2715 + */ + void verifyWritableTempDir() { + File file = null; + try { + file = File.createTempFile("sonarqube-check", "tmp"); + } catch (IOException e) { + throw new IllegalStateException("Unable to create file in temporary directory, please check existence " + + "and permissions of: " + FileUtils.getTempDirectory(), e); + } finally { + FileUtils.deleteQuietly(file); + } + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java b/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java deleted file mode 100644 index 975db243f04..00000000000 --- a/sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 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.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.NCSARequestLog; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; -import org.eclipse.jetty.server.handler.ShutdownHandler; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.webapp.WebAppContext; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Properties; - -public class JettyEmbedder { - - private final Server server; - private final String host; - private final int port; - private final String contextPath; - private final Properties configuration; - - public JettyEmbedder(String host, int port, String contextPath, Properties configuration) throws Exception { - this.host = host.trim(); - this.port = port; - this.contextPath = contextPath; - this.configuration = configuration; - server = new Server(); - configureProgrammatically(); - } - - /** - * for tests - */ - JettyEmbedder(String host, int port) throws Exception { - this(host, port, null, new Properties()); - } - - public void start() throws Exception { - server.start(); - - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - try { - server.stop(); - } catch (Exception e) { - System.err.println("Can not stop the Jetty server"); - e.printStackTrace(); - } - } - }); - } - - private Server configureProgrammatically() throws URISyntaxException { - configureServer(); - - List<Handler> handlers = new ArrayList<Handler>(); - - String shutdownCookie = System.getProperty("sonar.shutdownToken"); - if (shutdownCookie != null && !"".equals(shutdownCookie)) { - System.out.println("Registering shutdown handler"); - ShutdownHandler shutdownHandler = new ShutdownHandler(server, shutdownCookie); - shutdownHandler.setExitJvm(true); - handlers.add(shutdownHandler); - } - - WebAppContext context = new WebAppContext(getPath("/web"), contextPath); - // Set up the path to the custom webdefault.xml (SONAR-3962). - context.setDefaultsDescriptor("/org/sonar/application/webdefault.xml"); - handlers.add(context); - - String filenamePattern = configuration.getProperty("sonar.web.jettyRequestLogs"); - if (filenamePattern != null) { - handlers.add(configureRequestLogHandler(filenamePattern)); - } - - HandlerCollection handler = new HandlerCollection(); - handler.setHandlers(handlers.toArray(new Handler[handlers.size()])); - server.setHandler(handler); - - return server; - } - - private RequestLogHandler configureRequestLogHandler(String filenamePattern) { - RequestLogHandler requestLogHandler = new RequestLogHandler(); - NCSARequestLog requestLog = new NCSARequestLog(filenamePattern); - requestLog.setRetainDays(7); - requestLog.setAppend(true); - requestLog.setExtended(true); - requestLog.setLogTimeZone("GMT"); - requestLogHandler.setRequestLog(requestLog); - return requestLogHandler; - } - - private void configureServer() { - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setMinThreads(getIntProperty("sonar.web.jetty.threads.min", 5)); - threadPool.setMaxThreads(getIntProperty("sonar.web.jetty.threads.max", 50)); - server.setThreadPool(threadPool); - SelectChannelConnector connector = new SelectChannelConnector(); - connector.setHost(host); - connector.setPort(port); - connector.setStatsOn(false); - connector.setAcceptors(2); - connector.setConfidentialPort(8443); - server.addConnector(connector); - server.setStopAtShutdown(true); - server.setSendServerVersion(false); - server.setSendDateHeader(true); - server.setGracefulShutdown(1000); - } - - private int getIntProperty(String name, int defaultValue) { - String value = configuration.getProperty(name); - if (null == value) { - return defaultValue; - } - - return Integer.parseInt(value); - } - - final String getPluginsClasspath(String pluginsPathFromClassloader) throws URISyntaxException, IOException { - URL resource = getClass().getResource(pluginsPathFromClassloader); - if (resource == null) { - return null; - } - - List<String> paths = new ArrayList<String>(); - - File pluginsDir = new File(resource.toURI()); - paths.add(pluginsDir.getCanonicalPath() + System.getProperty("file.separator")); - - Collection<File> files = FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false); - for (File file : files) { - paths.add(file.getCanonicalPath()); - } - - return join(paths, ","); - } - - private String join(List<String> paths, String separator) { - StringBuilder sb = new StringBuilder(); - for (String path : paths) { - if (sb.length() > 0) { - sb.append(separator); - } - sb.append(path); - } - return sb.toString(); - } - - private String getPath(String resourcePath) throws URISyntaxException { - URL resource = getClass().getResource(resourcePath); - if (resource != null) { - return resource.toURI().toString(); - } - return null; - } - - Server getServer() { - return server; - } - - @Override - public String toString() { - return new StringBuilder().append("http://").append(host).append(":").append(port).append(contextPath).toString(); - } -} diff --git a/sonar-application/src/main/java/org/sonar/application/Logging.java b/sonar-application/src/main/java/org/sonar/application/Logging.java new file mode 100644 index 00000000000..29d8d097698 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Logging.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 ch.qos.logback.access.tomcat.LogbackValve; +import org.apache.catalina.startup.Tomcat; +import org.slf4j.bridge.SLF4JBridgeHandler; + +import java.io.File; +import java.util.logging.LogManager; + +class Logging { + + static final String CONF_PATH = "conf/logback-access.xml"; + + static void init() { + // Configure java.util.logging, used by Tomcat, in order to forward to slf4j + LogManager.getLogManager().reset(); + SLF4JBridgeHandler.install(); + } + + static void configure(Tomcat tomcat, Env env) { + tomcat.setSilent(false); + LogbackValve valve = new LogbackValve(); + valve.setQuiet(true); + File confFile = env.file(CONF_PATH); + if (!confFile.exists()) { + throw new IllegalStateException("File is missing: " + confFile.getAbsolutePath()); + } + valve.setFilename(confFile.getAbsolutePath()); + tomcat.getHost().getPipeline().addValve(valve); + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/NullJarScanner.java b/sonar-application/src/main/java/org/sonar/application/NullJarScanner.java new file mode 100644 index 00000000000..c6c82e2104d --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/NullJarScanner.java @@ -0,0 +1,35 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.tomcat.JarScanner; +import org.apache.tomcat.JarScannerCallback; + +import javax.servlet.ServletContext; +import java.util.Set; + +/** + * Disable taglib and web-fragment.xml scanning of Tomcat. Should speed up startup. + */ +class NullJarScanner implements JarScanner { + @Override + public void scan(ServletContext context, ClassLoader classloader, JarScannerCallback callback, Set<String> jarsToSkip) { + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/Props.java b/sonar-application/src/main/java/org/sonar/application/Props.java new file mode 100644 index 00000000000..a3d1a8b27e2 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Props.java @@ -0,0 +1,84 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.IOUtils; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +/** + * TODO support env substitution + */ +class Props { + private final Properties props; + + Props(Properties props) { + this.props = props; + } + + String of(String key) { + return props.getProperty(key); + } + + String of(String key, @Nullable String defaultValue) { + String s = of(key); + return s == null ? defaultValue : s; + } + + Integer intOf(String key) { + String s = of(key); + if (s != null && !"".equals(s)) { + try { + return Integer.parseInt(s); + } catch (NumberFormatException e) { + throw new IllegalStateException("Value of property " + key + " is not an integer: " + s, e); + } + } + return null; + } + + int intOf(String key, int defaultValue) { + Integer i = intOf(key); + return i == null ? defaultValue : i; + } + + static Props create(Env env) { + File propsFile = env.file("conf/sonar.properties"); + Properties p = new Properties(); + FileReader reader = null; + try { + reader = new FileReader(propsFile); + p.load(reader); + p.putAll(System.getProperties()); + return new Props(p); + + } catch (Exception e) { + throw new IllegalStateException("File does not exist or can't be open: " + propsFile, e); + + } finally { + IOUtils.closeQuietly(reader); + } + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/StartServer.java b/sonar-application/src/main/java/org/sonar/application/StartServer.java index 923f6ddd153..3704265007c 100644 --- a/sonar-application/src/main/java/org/sonar/application/StartServer.java +++ b/sonar-application/src/main/java/org/sonar/application/StartServer.java @@ -19,61 +19,33 @@ */ package org.sonar.application; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Properties; +// TODO dev mode +// TODO sanitize jetty dependencies +// TODO remove logback/slf4j from sonar-server public final class StartServer { - private static final String DEFAULT_WEB_HOST = "0.0.0.0"; - private static final int DEFAULT_WEB_PORT = 9000; - private static final String DEFAULT_WEB_CONTEXT = "/"; - private static final String PROPERTIES_FILE_PATH = "/conf/sonar.properties"; - - private StartServer() { - } - public static void main(String[] args) throws Exception { - canCreateTemporaryFiles(); - configureHome(); + private final EmbeddedTomcat tomcat; - Properties configuration = getConfiguration(); - String host = configuration.getProperty("sonar.web.host", DEFAULT_WEB_HOST); - int port = Integer.parseInt(configuration.getProperty("sonar.web.port", "" + DEFAULT_WEB_PORT)); - String context = configuration.getProperty("sonar.web.context", DEFAULT_WEB_CONTEXT); - JettyEmbedder jetty = new JettyEmbedder(host, port, context, configuration); + public StartServer(Env env) { + Logging.init(); + env.verifyWritableTempDir(); + this.tomcat = new EmbeddedTomcat(env); + } - jetty.start(); - Thread.currentThread().join(); + void start() throws Exception { + tomcat.start(); } - /** - * This check is required in order to provide more meaningful message than JRuby - see SONAR-2715 - */ - private static void canCreateTemporaryFiles() { - File file = null; - try { - file = File.createTempFile("sonar-check", "tmp"); - } catch (IOException e) { - throw new IllegalStateException("Unable to create file in temporary directory, please check existence of it and permissions: " + FileUtils.getTempDirectoryPath(), e); - } finally { - FileUtils.deleteQuietly(file); - } + int port() { + return tomcat.port(); } - private static Properties getConfiguration() throws IOException { - Properties properties = new Properties(); - properties.load(StartServer.class.getResourceAsStream(PROPERTIES_FILE_PATH)); - return properties; + void stop() throws Exception { + tomcat.stop(); } - /** - * @see org.sonar.server.platform.SonarHome#SONAR_HOME - */ - private static void configureHome() throws URISyntaxException { - File confFile = new File(StartServer.class.getResource(PROPERTIES_FILE_PATH).toURI()); - System.setProperty("SONAR_HOME", confFile.getParentFile().getParentFile().getAbsolutePath()); + public static void main(String[] args) throws Exception { + new StartServer(new Env()).start(); } } diff --git a/sonar-application/src/main/java/org/sonar/application/Webapp.java b/sonar-application/src/main/java/org/sonar/application/Webapp.java new file mode 100644 index 00000000000..70d33d829b5 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/Webapp.java @@ -0,0 +1,39 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.catalina.Context; +import org.apache.catalina.startup.Tomcat; + +class Webapp { + + static void configure(Tomcat tomcat, Env env, Props props) { + String ctx = props.of("sonar.web.context", "/"); + try { + System.setProperty("SONAR_HOME", env.rootDir().getAbsolutePath()); + Context context = tomcat.addWebapp(ctx, env.file("web").getAbsolutePath()); + context.setConfigFile(env.file("web/META-INF/context.xml").toURL()); + context.setJarScanner(new NullJarScanner()); + + } catch (Exception e) { + throw new IllegalStateException("Fail to configure webapp", e); + } + } +} diff --git a/sonar-application/src/main/java/org/sonar/application/package-info.java b/sonar-application/src/main/java/org/sonar/application/package-info.java new file mode 100644 index 00000000000..009b187eda5 --- /dev/null +++ b/sonar-application/src/main/java/org/sonar/application/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.application; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-application/src/main/resources/org/sonar/application/webdefault.xml b/sonar-application/src/main/resources/org/sonar/application/webdefault.xml deleted file mode 100644 index 75599d24cb4..00000000000 --- a/sonar-application/src/main/resources/org/sonar/application/webdefault.xml +++ /dev/null @@ -1,347 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> - - <!-- Modified version of webdefault.xml shipped inside jetty-webapp in order to remove JSP servlet --> - - <!-- ===================================================================== --> - <!-- This file contains the default descriptor for web applications. --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- The intent of this descriptor is to include jetty specific or common --> - <!-- configuration for all webapps. If a context has a webdefault.xml --> - <!-- descriptor, it is applied before the contexts own web.xml file --> - <!-- --> - <!-- A context may be assigned a default descriptor by: --> - <!-- + Calling WebApplicationContext.setDefaultsDescriptor --> - <!-- + Passed an arg to addWebApplications --> - <!-- --> - <!-- This file is used both as the resource within the jetty.jar (which is --> - <!-- used as the default if no explicit defaults descriptor is set) and it --> - <!-- is copied to the etc directory of the Jetty distro and explicitly --> - <!-- by the jetty.xml file. --> - <!-- --> - <!-- ===================================================================== --> -<web-app - xmlns="http://java.sun.com/xml/ns/javaee" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" - metadata-complete="true" - version="2.5" -> - - <description> - Default web.xml file. - This file is applied to a Web application before it's own WEB_INF/web.xml file - </description> - - <!-- ==================================================================== --> - <!-- Removes static references to beans from javax.el.BeanELResolver to --> - <!-- ensure webapp classloader can be released on undeploy --> - <!-- ==================================================================== --> - <listener> - <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class> - </listener> - - <!-- ==================================================================== --> - <!-- Removes static cache of Methods from java.beans.Introspector to --> - <!-- ensure webapp classloader can be released on undeploy --> - <!-- ==================================================================== --> - <listener> - <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class> - </listener> - - <!-- ==================================================================== --> - <!-- The default servlet. --> - <!-- This servlet, normally mapped to /, provides the handling for static --> - <!-- content, OPTIONS and TRACE methods for the context. --> - <!-- The following initParameters are supported: --> - <!-- - * acceptRanges If true, range requests and responses are - * supported - * - * dirAllowed If true, directory listings are returned if no - * welcome file is found. Else 403 Forbidden. - * - * welcomeServlets If true, attempt to dispatch to welcome files - * that are servlets, but only after no matching static - * resources could be found. If false, then a welcome - * file must exist on disk. If "exact", then exact - * servlet matches are supported without an existing file. - * Default is true. - * - * This must be false if you want directory listings, - * but have index.jsp in your welcome file list. - * - * redirectWelcome If true, welcome files are redirected rather than - * forwarded to. - * - * gzip If set to true, then static content will be served as - * gzip content encoded if a matching resource is - * found ending with ".gz" - * - * resourceBase Set to replace the context resource base - * - * resourceCache If set, this is a context attribute name, which the servlet - * will use to look for a shared ResourceCache instance. - * - * relativeResourceBase - * Set with a pathname relative to the base of the - * servlet context root. Useful for only serving static content out - * of only specific subdirectories. - * - * aliases If True, aliases of resources are allowed (eg. symbolic - * links and caps variations). May bypass security constraints. - * - * maxCacheSize The maximum total size of the cache or 0 for no cache. - * maxCachedFileSize The maximum size of a file to cache - * maxCachedFiles The maximum number of files to cache - * - * useFileMappedBuffer - * If set to true, it will use mapped file buffer to serve static content - * when using NIO connector. Setting this value to false means that - * a direct buffer will be used instead of a mapped file buffer. - * By default, this is set to true. - * - * cacheControl If set, all static content will have this value set as the cache-control - * header. - --> - - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <servlet> - <servlet-name>default</servlet-name> - <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class> - <init-param> - <param-name>aliases</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>acceptRanges</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>dirAllowed</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>welcomeServlets</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>redirectWelcome</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>maxCacheSize</param-name> - <param-value>256000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFileSize</param-name> - <param-value>200000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFiles</param-name> - <param-value>2048</param-value> - </init-param> - <init-param> - <param-name>gzip</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>useFileMappedBuffer</param-name> - <param-value>true</param-value> - </init-param> - <!-- - <init-param> - <param-name>resourceCache</param-name> - <param-value>resourceCache</param-value> - </init-param> - --> - <!-- - <init-param> - <param-name>cacheControl</param-name> - <param-value>max-age=3600,public</param-value> - </init-param> - --> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> - <servlet-name>default</servlet-name> - <url-pattern>/</url-pattern> - </servlet-mapping> - - - <!-- ==================================================================== --> - <session-config> - <session-timeout>30</session-timeout> - </session-config> - - <!-- ==================================================================== --> - <locale-encoding-mapping-list> - <locale-encoding-mapping> - <locale>ar</locale> - <encoding>ISO-8859-6</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>be</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>bg</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ca</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>cs</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>da</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>de</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>el</locale> - <encoding>ISO-8859-7</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>en</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>es</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>et</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>fi</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>fr</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>hr</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>hu</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>is</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>it</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>iw</locale> - <encoding>ISO-8859-8</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ja</locale> - <encoding>Shift_JIS</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ko</locale> - <encoding>EUC-KR</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>lt</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>lv</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>mk</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>nl</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>no</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>pl</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>pt</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ro</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ru</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sh</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sk</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sl</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sq</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sr</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sv</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>tr</locale> - <encoding>ISO-8859-9</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>uk</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>zh</locale> - <encoding>GB2312</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>zh_TW</locale> - <encoding>Big5</encoding> - </locale-encoding-mapping> - </locale-encoding-mapping-list> - - <security-constraint> - <web-resource-collection> - <web-resource-name>Disable TRACE</web-resource-name> - <url-pattern>/</url-pattern> - <http-method>TRACE</http-method> - </web-resource-collection> - <auth-constraint/> - </security-constraint> - -</web-app> diff --git a/sonar-application/src/test/fake-app/conf/logback-access.xml b/sonar-application/src/test/fake-app/conf/logback-access.xml new file mode 100644 index 00000000000..77cfc885d09 --- /dev/null +++ b/sonar-application/src/test/fake-app/conf/logback-access.xml @@ -0,0 +1,17 @@ +<!-- + + See http://logback.qos.ch/access.html#configuration + +--> +<configuration debug="false"> + <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> + + <appender name="FILE" class="ch.qos.logback.core.FileAppender"> + <file>${SONAR_HOME}/logs/access.log</file> + <encoder> + <pattern>combined</pattern> + </encoder> + </appender> + + <appender-ref ref="FILE" /> +</configuration> diff --git a/sonar-application/src/test/fake-app/conf/sonar.properties b/sonar-application/src/test/fake-app/conf/sonar.properties new file mode 100644 index 00000000000..e8e111dcab8 --- /dev/null +++ b/sonar-application/src/test/fake-app/conf/sonar.properties @@ -0,0 +1,2 @@ +# random open port +sonar.web.port=0
\ No newline at end of file diff --git a/sonar-application/src/test/fake-app/web/META-INF/context.xml b/sonar-application/src/test/fake-app/web/META-INF/context.xml new file mode 100644 index 00000000000..5e31888a15e --- /dev/null +++ b/sonar-application/src/test/fake-app/web/META-INF/context.xml @@ -0,0 +1,2 @@ +<Context antiJARLocking="true" antiResourceLocking="true"> +</Context> diff --git a/sonar-application/src/test/fake-app/web/WEB-INF/web.xml b/sonar-application/src/test/fake-app/web/WEB-INF/web.xml new file mode 100644 index 00000000000..9f13dabf72f --- /dev/null +++ b/sonar-application/src/test/fake-app/web/WEB-INF/web.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://java.sun.com/xml/ns/javaee" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + id="Fake" + version="3.0" + metadata-complete="true"> + + <display-name>Fake</display-name> + +</web-app> diff --git a/sonar-application/src/test/fake-app/web/index.html b/sonar-application/src/test/fake-app/web/index.html new file mode 100644 index 00000000000..5e1c309dae7 --- /dev/null +++ b/sonar-application/src/test/fake-app/web/index.html @@ -0,0 +1 @@ +Hello World
\ No newline at end of file diff --git a/sonar-application/src/test/java/org/sonar/application/ConnectorsTest.java b/sonar-application/src/test/java/org/sonar/application/ConnectorsTest.java new file mode 100644 index 00000000000..b437227211f --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/ConnectorsTest.java @@ -0,0 +1,102 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.catalina.connector.Connector; +import org.apache.catalina.startup.Tomcat; +import org.junit.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.Mockito; + +import java.util.Properties; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +public class ConnectorsTest { + @Test + public void enable_shutdown_port() throws Exception { + Properties p = new Properties(); + p.setProperty(Connectors.PROPERTY_SHUTDOWN_PORT, "9010"); + p.setProperty(Connectors.PROPERTY_SHUTDOWN_TOKEN, "SHUTDOWN"); + Props props = new Props(p); + + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Connectors.configure(tomcat, props); + + verify(tomcat.getServer()).setPort(9010); + verify(tomcat.getServer()).setShutdown("SHUTDOWN"); + } + + @Test + public void disable_shutdown_port_by_default() throws Exception { + Props props = new Props(new Properties()); + + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Connectors.configure(tomcat, props); + + verify(tomcat.getServer(), never()).setPort(anyInt()); + verify(tomcat.getServer(), never()).setShutdown(anyString()); + } + + @Test + public void configure_thread_pool() throws Exception { + Properties p = new Properties(); + p.setProperty(Connectors.PROPERTY_MIN_THREADS, "2"); + p.setProperty(Connectors.PROPERTY_MAX_THREADS, "30"); + p.setProperty(Connectors.PROPERTY_ACCEPT_COUNT, "20"); + Props props = new Props(p); + + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Connectors.configure(tomcat, props); + + verify(tomcat).setConnector(argThat(new ArgumentMatcher<Connector>() { + @Override + public boolean matches(Object o) { + Connector c = (Connector)o; + return (Integer)c.getProperty("minSpareThreads") == 2 && + (Integer) c.getProperty("maxThreads") == 30 && + (Integer) c.getProperty("acceptCount") == 20; + } + })); + } + + @Test + public void configure_default_thread_pool() throws Exception { + Props props = new Props(new Properties()); + + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Connectors.configure(tomcat, props); + + verify(tomcat).setConnector(argThat(new ArgumentMatcher<Connector>() { + @Override + public boolean matches(Object o) { + Connector c = (Connector)o; + return (Integer)c.getProperty("minSpareThreads") == 5 && + (Integer) c.getProperty("maxThreads") == 50 && + (Integer) c.getProperty("acceptCount") == 25; + } + })); + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/EnvTest.java b/sonar-application/src/test/java/org/sonar/application/EnvTest.java new file mode 100644 index 00000000000..0aab59fa26e --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/EnvTest.java @@ -0,0 +1,80 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class EnvTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void files() throws Exception { + File home = temp.newFolder(); + File confFile = new File(home, "conf/sonar.properties"); + File logFile = new File(home, "logs/sonar.log"); + + FileUtils.touch(confFile); + FileUtils.touch(logFile); + + Env env = new Env(confFile); + + assertThat(env.rootDir()).isDirectory().exists().isEqualTo(home); + assertThat(env.file("conf/sonar.properties")).isFile().exists().isEqualTo(confFile); + assertThat(env.file("logs/sonar.log")).isFile().exists().isEqualTo(logFile); + assertThat(env.file("xxx/unknown.log")).doesNotExist(); + } + + @Test + public void fresh_dir() throws Exception { + File home = temp.newFolder(); + File confFile = new File(home, "conf/sonar.properties"); + File logFile = new File(home, "logs/sonar.log"); + + FileUtils.touch(confFile); + FileUtils.touch(logFile); + + Env env = new Env(confFile); + + File data = env.freshDir("data/h2"); + assertThat(data).isDirectory().exists(); + assertThat(data.getParentFile().getName()).isEqualTo("data"); + assertThat(data.getParentFile().getParentFile()).isEqualTo(home); + + // clean directory + File logs = env.freshDir("logs"); + assertThat(logs).isDirectory().exists(); + assertThat(logs.listFiles()).isEmpty(); + } + + @Test + public void temp_dir_should_be_writable() throws Exception { + new Env(temp.newFile()).verifyWritableTempDir(); + // do not fail + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/JettyEmbedderTest.java b/sonar-application/src/test/java/org/sonar/application/JettyEmbedderTest.java deleted file mode 100644 index 5c7a35e163c..00000000000 --- a/sonar-application/src/test/java/org/sonar/application/JettyEmbedderTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2013 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.lang.StringUtils; -import org.junit.Test; - -import static org.fest.assertions.Assertions.assertThat; - -public class JettyEmbedderTest { - - @Test - public void shouldConfigureProgrammatically() throws Exception { - JettyEmbedder jetty = new JettyEmbedder("1.2.3.4", 9999); - - assertThat(jetty.getServer().getConnectors()).hasSize(1); - assertThat(jetty.getServer().getConnectors()[0].getPort()).isEqualTo(9999); - assertThat(jetty.getServer().getConnectors()[0].getHost()).isEqualTo("1.2.3.4"); - } - - @Test - public void shouldLoadPluginsClasspath() throws Exception { - JettyEmbedder jetty = new JettyEmbedder("127.0.0.1", 9999); - - String classpath = jetty.getPluginsClasspath("/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath"); - classpath = StringUtils.replaceChars(classpath, "\\", "/"); - - assertThat(classpath).contains("org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin1.jar"); - assertThat(classpath).contains("org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin1.jar"); - assertThat(classpath).contains("org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin2.jar"); - - // important : directories end with / - assertThat(classpath).contains("org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/,"); - } -} diff --git a/sonar-application/src/test/java/org/sonar/application/LoggingTest.java b/sonar-application/src/test/java/org/sonar/application/LoggingTest.java new file mode 100644 index 00000000000..ca5f6ef3c51 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/LoggingTest.java @@ -0,0 +1,68 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 ch.qos.logback.access.tomcat.LogbackValve; +import org.apache.catalina.Valve; +import org.apache.catalina.startup.Tomcat; +import org.junit.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.Mockito; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.*; + +public class LoggingTest { + @Test + public void configure_access_logs() throws Exception { + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Env env = mock(Env.class); + final File propsFile = new File(getClass().getResource("/org/sonar/application/LoggingTest/logback-access.xml").toURI()); + when(env.file(Logging.CONF_PATH)).thenReturn(propsFile); + Logging.configure(tomcat, env); + + verify(tomcat.getHost().getPipeline()).addValve(argThat(new ArgumentMatcher<Valve>() { + @Override + public boolean matches(Object o) { + LogbackValve v = (LogbackValve) o; + return v.getFilename().equals(propsFile.getAbsolutePath()); + } + })); + } + + @Test + public void fail_if_missing_conf_file() throws Exception { + Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); + Env env = mock(Env.class); + final File confFile = new File("target/does_not_exist/logback-access.xml"); + when(env.file(Logging.CONF_PATH)).thenReturn(confFile); + + try { + Logging.configure(tomcat, env); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("File is missing: " + confFile.getAbsolutePath()); + } + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/NullJarScannerTest.java b/sonar-application/src/test/java/org/sonar/application/NullJarScannerTest.java new file mode 100644 index 00000000000..50e3a9a60d0 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/NullJarScannerTest.java @@ -0,0 +1,43 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.tomcat.JarScannerCallback; +import org.junit.Test; + +import javax.servlet.ServletContext; +import java.util.HashSet; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; + +public class NullJarScannerTest { + + @Test + public void does_nothing() { + ServletContext context = mock(ServletContext.class); + ClassLoader classloader = mock(ClassLoader.class); + JarScannerCallback callback = mock(JarScannerCallback.class); + + new NullJarScanner().scan(context, classloader, callback, new HashSet<String>()); + + verifyZeroInteractions(context, classloader, callback); + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/PropsTest.java b/sonar-application/src/test/java/org/sonar/application/PropsTest.java new file mode 100644 index 00000000000..b2bd5d0fd69 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/PropsTest.java @@ -0,0 +1,98 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.junit.Test; + +import java.io.File; +import java.util.Properties; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PropsTest { + @Test + public void of() throws Exception { + Properties p = new Properties(); + p.setProperty("foo", "bar"); + Props props = new Props(p); + + assertThat(props.of("foo")).isEqualTo("bar"); + assertThat(props.of("foo", "default value")).isEqualTo("bar"); + assertThat(props.of("unknown")).isNull(); + assertThat(props.of("unknown", "default value")).isEqualTo("default value"); + } + + @Test + public void intOf() throws Exception { + Properties p = new Properties(); + p.setProperty("foo", "33"); + Props props = new Props(p); + + assertThat(props.intOf("foo")).isEqualTo(33); + assertThat(props.intOf("foo", 44)).isEqualTo(33); + assertThat(props.intOf("unknown")).isNull(); + assertThat(props.intOf("unknown", 44)).isEqualTo(44); + } + + @Test + public void intOf_not_integer() throws Exception { + Properties p = new Properties(); + p.setProperty("foo", "bar"); + Props props = new Props(p); + + try { + props.intOf("foo"); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("Value of property foo is not an integer: bar"); + } + } + + @Test + public void load_file_and_system_properties() throws Exception { + Env env = mock(Env.class); + File propsFile = new File(getClass().getResource("/org/sonar/application/PropsTest/sonar.properties").toURI()); + when(env.file("conf/sonar.properties")).thenReturn(propsFile); + + Props props = Props.create(env); + + assertThat(props.of("foo")).isEqualTo("bar"); + assertThat(props.of("java.version")).isNotNull(); + + // system properties override file properties + assertThat(props.of("java.io.tmpdir")).isNotEmpty().isNotEqualTo("/should/be/overridden"); + } + + @Test + public void fail_if_file_does_not_exist() throws Exception { + Env env = mock(Env.class); + when(env.file("conf/sonar.properties")).thenReturn(new File("target/not_exist/sonar.properties")); + + try { + Props.create(env); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("File does not exist or can't be open: target/not_exist/sonar.properties"); + } + } +} diff --git a/sonar-application/src/test/java/org/sonar/application/StartServerTest.java b/sonar-application/src/test/java/org/sonar/application/StartServerTest.java new file mode 100644 index 00000000000..868a51288d2 --- /dev/null +++ b/sonar-application/src/test/java/org/sonar/application/StartServerTest.java @@ -0,0 +1,150 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 com.github.kevinsawicki.http.HttpRequest; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class StartServerTest { + + Env env = new Env(locateFakeConfFile()); + StartServer starter = new StartServer(env); + + @Before + @After + public void clean_generated_dirs() throws IOException { + FileUtils.deleteDirectory(env.file("temp")); + FileUtils.deleteDirectory(env.file("logs")); + } + + @Test + public void start_server() throws Exception { + BackgroundThread background = new BackgroundThread(starter); + int port = 0; + try { + background.start(); + boolean started = false; + for (int i = 0; i < 100; i++) { + // Waiting for server to be started. + // A random and open port is used (see conf/sonar.properties) + Thread.sleep(500L); + if (verifyUp() && verifyLogs()) { + port = starter.port(); + started = true; + break; + } + } + assertThat(started).isTrue(); + } finally { + starter.stop(); + } + + // Server is down + try { + assertThat(HttpRequest.get("http://localhost:" + port).ok()).isFalse(); + } catch (HttpRequest.HttpRequestException e) { + // ok + } + } + + private boolean verifyUp() { + if (starter.port() > 0) { + String url = "http://localhost:" + starter.port() + "/index.html"; + HttpRequest request = HttpRequest.get(url); + if (request.ok() && "Hello World".equals(request.body(HttpRequest.CHARSET_UTF8))) { + return true; + } + } + return false; + } + + private boolean verifyLogs() { + File logFile = env.file("logs/access.log"); + return logFile.isFile() && logFile.exists() && logFile.length()>0; + } + + @Test + public void fail_if_started_twice() throws Exception { + BackgroundThread background = new BackgroundThread(starter); + try { + background.start(); + boolean started = false; + for (int i = 0; i < 100; i++) { + // Waiting for server to be started. + // A random and open port is used (see conf/sonar.properties) + Thread.sleep(500L); + if (starter.port() > 0) { + try { + starter.start(); + fail(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("Tomcat is already started"); + started = true; + break; + } + } + } + assertThat(started).isTrue(); + + } finally { + starter.stop(); + } + } + + @Test + public void ignore_stop_if_not_running() throws Exception { + starter.stop(); + starter.stop(); + } + + private File locateFakeConfFile() { + File confFile = new File("src/test/fake-app/conf/sonar.properties"); + if (!confFile.exists()) { + confFile = new File("sonar-application/src/test/fake-app/conf/sonar.properties"); + } + return confFile; + } + + static class BackgroundThread extends Thread { + private StartServer server; + + BackgroundThread(StartServer server) { + this.server = server; + } + + @Override + public void run() { + try { + server.start(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/foo.xml b/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/foo.xml deleted file mode 100644 index e69de29bb2d..00000000000 --- a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/foo.xml +++ /dev/null diff --git a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin1.jar b/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin1.jar deleted file mode 100644 index e69de29bb2d..00000000000 --- a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin1.jar +++ /dev/null diff --git a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin2.jar b/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin2.jar deleted file mode 100644 index e69de29bb2d..00000000000 --- a/sonar-application/src/test/resources/org/sonar/application/JettyEmbedderTest/shouldLoadPluginsClasspath/plugin2.jar +++ /dev/null diff --git a/sonar-application/src/test/resources/org/sonar/application/LoggingTest/logback-access.xml b/sonar-application/src/test/resources/org/sonar/application/LoggingTest/logback-access.xml new file mode 100644 index 00000000000..298193e01fa --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/LoggingTest/logback-access.xml @@ -0,0 +1 @@ +<configuration/> diff --git a/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties b/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties new file mode 100644 index 00000000000..b73be15411b --- /dev/null +++ b/sonar-application/src/test/resources/org/sonar/application/PropsTest/sonar.properties @@ -0,0 +1,2 @@ +foo=bar +java.io.tmpdir=/should/be/overridden diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index 4c86b9e75f0..8d22fc02e7a 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -13,6 +13,11 @@ <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>com.akiban</groupId> <artifactId>akiban-persistit</artifactId> </dependency> @@ -94,8 +99,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> <scope>test</scope> </dependency> <dependency> diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml index 9712a01ce2e..2e52b7506c5 100644 --- a/sonar-core/pom.xml +++ b/sonar-core/pom.xml @@ -15,6 +15,11 @@ <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>${project.groupId}</groupId> <artifactId>sonar-plugin-api</artifactId> <exclusions> diff --git a/sonar-plugin-api/pom.xml b/sonar-plugin-api/pom.xml index 7d885fcb6eb..494d2291242 100644 --- a/sonar-plugin-api/pom.xml +++ b/sonar-plugin-api/pom.xml @@ -14,6 +14,11 @@ <name>SonarQube :: Plugin API</name> <dependencies> <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.codehaus.sonar</groupId> <artifactId>sonar-check-api</artifactId> </dependency> @@ -126,8 +131,9 @@ <artifactId>xalan</artifactId> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.0.1</version> <optional>true</optional> </dependency> diff --git a/sonar-server/h2-start.sh b/sonar-server/h2-start.sh index 9e2b5835df6..681987b24ae 100755 --- a/sonar-server/h2-start.sh +++ b/sonar-server/h2-start.sh @@ -1,3 +1,3 @@ #!/bin/sh export MAVEN_OPTS='-Xmx768m -XX:MaxPermSize=128m' -mvn clean jetty:run -Pstart-dev-server,h2 $* +mvn clean org.apache.tomcat.maven:tomcat7-maven-plugin::run -Pstart-dev-server,h2 $* diff --git a/sonar-server/pom.xml b/sonar-server/pom.xml index 7b14a4d60ca..271bdc3d315 100644 --- a/sonar-server/pom.xml +++ b/sonar-server/pom.xml @@ -114,11 +114,6 @@ <artifactId>commons-codec</artifactId> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> - <scope>provided</scope> - </dependency> - <dependency> <groupId>jfree</groupId> <artifactId>jfreechart</artifactId> </dependency> @@ -135,11 +130,16 @@ <artifactId>jruby-rack</artifactId> </dependency> <dependency> - <!-- GZIP filter --> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlets</artifactId> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>7.0.42</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> </dependency> - <!-- unit tests --> <dependency> <groupId>org.codehaus.sonar</groupId> @@ -374,26 +374,18 @@ </executions> </plugin> <plugin> - <groupId>org.mortbay.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>${jetty.version}</version> + <groupId>org.apache.tomcat.maven</groupId> + <artifactId>tomcat7-maven-plugin</artifactId> + <version>2.1</version> <configuration> - <webAppConfig> - <contextPath>/dev</contextPath> - <defaultsDescriptor>${basedir}/src/dev/webdefault.xml</defaultsDescriptor> - <descriptor>${basedir}/src/dev/web.xml</descriptor> - </webAppConfig> - <connectors> - <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector"> - <port>9000</port> - <maxIdleTime>60000</maxIdleTime> - </connector> - </connectors> + <port>9000</port> + <path>/dev</path> + <!--<contextFile>${pom.basedir}/src/main/webapp/META-INF/context.xml</contextFile>--> + <tomcatWebXml>${pom.basedir}/src/dev/web.xml</tomcatWebXml> + <useNaming>false</useNaming> <systemProperties> - <systemProperty> - <name>SONAR_HOME</name> - <value>${project.build.directory}/sonar-dev-home</value> - </systemProperty> + <SONAR_HOME>${pom.build.directory}/sonar-dev-home</SONAR_HOME> + <!--<java.io.tmpdir>${pom.basedir}/target/tomcat-tmp</java.io.tmpdir>--> </systemProperties> </configuration> </plugin> diff --git a/sonar-server/src/dev/web.xml b/sonar-server/src/dev/web.xml index 77bc34d5f59..d6ec5654caf 100644 --- a/sonar-server/src/dev/web.xml +++ b/sonar-server/src/dev/web.xml @@ -2,7 +2,9 @@ <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" - id="SonarQube" version="3.0"> + id="SonarQube" + version="3.0" + metadata-complete="true"> <display-name>SonarQube</display-name> <context-param> diff --git a/sonar-server/src/dev/webdefault.xml b/sonar-server/src/dev/webdefault.xml deleted file mode 100644 index 3967afba965..00000000000 --- a/sonar-server/src/dev/webdefault.xml +++ /dev/null @@ -1,507 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> - - <!-- ===================================================================== --> - <!-- This file contains the default descriptor for web applications. --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- The intent of this descriptor is to include jetty specific or common --> - <!-- configuration for all webapps. If a context has a webdefault.xml --> - <!-- descriptor, it is applied before the contexts own web.xml file --> - <!-- --> - <!-- A context may be assigned a default descriptor by: --> - <!-- + Calling WebApplicationContext.setDefaultsDescriptor --> - <!-- + Passed an arg to addWebApplications --> - <!-- --> - <!-- This file is used both as the resource within the jetty.jar (which is --> - <!-- used as the default if no explicit defaults descriptor is set) and it --> - <!-- is copied to the etc directory of the Jetty distro and explicitly --> - <!-- by the jetty.xml file. --> - <!-- --> - <!-- ===================================================================== --> -<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="http://java.sun.com/xml/ns/javaee" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" - id="SonarQube" version="3.0"> - - <description> - Default web.xml file. - This file is applied to a Web application before it's own WEB_INF/web.xml file - </description> - - - <!-- ==================================================================== --> - <!-- Context params to control Session Cookies --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- - UNCOMMENT TO ACTIVATE <context-param> <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> <param-value>127.0.0.1</param-value> </context-param> <context-param> - <param-name>org.eclipse.jetty.servlet.SessionPath</param-name> <param-value>/</param-value> </context-param> <context-param> <param-name>org.eclipse.jetty.servlet.MaxAge</param-name> - <param-value>-1</param-value> </context-param> - --> - - - <!-- ==================================================================== --> - <!-- The default servlet. --> - <!-- This servlet, normally mapped to /, provides the handling for static --> - <!-- content, OPTIONS and TRACE methods for the context. --> - <!-- The following initParameters are supported: --> - <!-- --> - <!-- aliases If true, aliases like symlinks are allowed. Note --> - <!-- that security constraints might be bypassed by --> - <!-- aliases static content. --> - <!-- --> - <!-- acceptRanges If true, range requests and responses are --> - <!-- supported --> - <!-- --> - <!-- dirAllowed If true, directory listings are returned if no --> - <!-- welcome file is found. Else 403 Forbidden. --> - <!-- --> - <!-- welcomeServlets If true, attempt to dispatch to welcome files --> - <!-- that are servlets, if no matching static --> - <!-- resources can be found. --> - <!-- --> - <!-- redirectWelcome If true, redirect welcome file requests --> - <!-- else use request dispatcher forwards --> - <!-- --> - <!-- gzip If set to true, then static content will be served--> - <!-- as gzip content encoded if a matching resource is --> - <!-- found ending with ".gz" --> - <!-- --> - <!-- resoureBase Can be set to replace the context resource base --> - <!-- --> - <!-- relativeResourceBase --> - <!-- Set with a pathname relative to the base of the --> - <!-- servlet context root. Useful for only serving --> - <!-- static content from only specific subdirectories. --> - <!-- --> - <!-- useFileMappedBuffer --> - <!-- If set to true (the default), a memory mapped --> - <!-- file buffer will be used to serve static content --> - <!-- when using an NIO connector. Setting this value --> - <!-- to false means that a direct buffer will be used --> - <!-- instead. If you are having trouble with Windows --> - <!-- file locking, set this to false. --> - <!-- --> - <!-- cacheControl If set, all static content will have this value --> - <!-- set as the cache-control header. --> - <!-- --> - <!-- maxCacheSize Maximum size of the static resource cache --> - <!-- --> - <!-- maxCachedFileSize Maximum size of any single file in the cache --> - <!-- --> - <!-- maxCachedFiles Maximum number of files in the cache --> - <!-- --> - <!-- cacheType "nio", "bio" or "both" to determine the type(s) --> - <!-- of resource cache. A bio cached buffer may be used--> - <!-- by nio but is not as efficient as a nio buffer. --> - <!-- An nio cached buffer may not be used by bio. --> - <!-- --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <servlet> - <servlet-name>default</servlet-name> - <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class> - <init-param> - <param-name>aliases</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>acceptRanges</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>dirAllowed</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <param-name>welcomeServlets</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>redirectWelcome</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>maxCacheSize</param-name> - <param-value>256000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFileSize</param-name> - <param-value>10000000</param-value> - </init-param> - <init-param> - <param-name>maxCachedFiles</param-name> - <param-value>1000</param-value> - </init-param> - <init-param> - <param-name>cacheType</param-name> - <param-value>both</param-value> - </init-param> - <init-param> - <param-name>gzip</param-name> - <param-value>true</param-value> - </init-param> - <init-param> - <!-- Prevent lock of static resources on Windows in dev mode - see SONAR-2247 --> - <param-name>useFileMappedBuffer</param-name> - <param-value>false</param-value> - </init-param> - <!-- - <init-param> - <param-name>cacheControl</param-name> - <param-value>max-age=3600,public</param-value> - </init-param> - --> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> - <servlet-name>default</servlet-name> - <url-pattern>/</url-pattern> - </servlet-mapping> - - - <!-- ==================================================================== --> - <!-- JSP Servlet --> - <!-- This is the jasper JSP servlet from the jakarta project --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- The JSP page compiler and execution servlet, which is the mechanism --> - <!-- used by Glassfish to support JSP pages. Traditionally, this servlet --> - <!-- is mapped to URL patterh "*.jsp". This servlet supports the --> - <!-- following initialization parameters (default values are in square --> - <!-- brackets): --> - <!-- --> - <!-- checkInterval If development is false and reloading is true, --> - <!-- background compiles are enabled. checkInterval --> - <!-- is the time in seconds between checks to see --> - <!-- if a JSP page needs to be recompiled. [300] --> - <!-- --> - <!-- compiler Which compiler Ant should use to compile JSP --> - <!-- pages. See the Ant documenation for more --> - <!-- information. [javac] --> - <!-- --> - <!-- classdebuginfo Should the class file be compiled with --> - <!-- debugging information? [true] --> - <!-- --> - <!-- classpath What class path should I use while compiling --> - <!-- generated servlets? [Created dynamically --> - <!-- based on the current web application] --> - <!-- Set to ? to make the container explicitly set --> - <!-- this parameter. --> - <!-- --> - <!-- development Is Jasper used in development mode (will check --> - <!-- for JSP modification on every access)? [true] --> - <!-- --> - <!-- enablePooling Determines whether tag handler pooling is --> - <!-- enabled [true] --> - <!-- --> - <!-- fork Tell Ant to fork compiles of JSP pages so that --> - <!-- a separate JVM is used for JSP page compiles --> - <!-- from the one Tomcat is running in. [true] --> - <!-- --> - <!-- ieClassId The class-id value to be sent to Internet --> - <!-- Explorer when using <jsp:plugin> tags. --> - <!-- [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93] --> - <!-- --> - <!-- javaEncoding Java file encoding to use for generating java --> - <!-- source files. [UTF-8] --> - <!-- --> - <!-- keepgenerated Should we keep the generated Java source code --> - <!-- for each page instead of deleting it? [true] --> - <!-- --> - <!-- logVerbosityLevel The level of detailed messages to be produced --> - <!-- by this servlet. Increasing levels cause the --> - <!-- generation of more messages. Valid values are --> - <!-- FATAL, ERROR, WARNING, INFORMATION, and DEBUG. --> - <!-- [WARNING] --> - <!-- --> - <!-- mappedfile Should we generate static content with one --> - <!-- print statement per input line, to ease --> - <!-- debugging? [false] --> - <!-- --> - <!-- --> - <!-- reloading Should Jasper check for modified JSPs? [true] --> - <!-- --> - <!-- suppressSmap Should the generation of SMAP info for JSR45 --> - <!-- debugging be suppressed? [false] --> - <!-- --> - <!-- dumpSmap Should the SMAP info for JSR45 debugging be --> - <!-- dumped to a file? [false] --> - <!-- False if suppressSmap is true --> - <!-- --> - <!-- scratchdir What scratch directory should we use when --> - <!-- compiling JSP pages? [default work directory --> - <!-- for the current web application] --> - <!-- --> - <!-- tagpoolMaxSize The maximum tag handler pool size [5] --> - <!-- --> - <!-- xpoweredBy Determines whether X-Powered-By response --> - <!-- header is added by generated servlet [false] --> - <!-- --> - <!-- If you wish to use Jikes to compile JSP pages: --> - <!-- Set the init parameter "compiler" to "jikes". Define --> - <!-- the property "-Dbuild.compiler.emacs=true" when starting Jetty --> - <!-- to cause Jikes to emit error messages in a format compatible with --> - <!-- Jasper. --> - <!-- If you get an error reporting that jikes can't use UTF-8 encoding, --> - <!-- try setting the init parameter "javaEncoding" to "ISO-8859-1". --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <servlet - id="jsp" - > - <servlet-name>jsp</servlet-name> - <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> - <init-param> - <param-name>logVerbosityLevel</param-name> - <param-value>DEBUG</param-value> - </init-param> - <init-param> - <param-name>fork</param-name> - <param-value>false</param-value> - </init-param> - <init-param> - <param-name>xpoweredBy</param-name> - <param-value>false</param-value> - </init-param> - <!-- - <init-param> - <param-name>classpath</param-name> - <param-value>?</param-value> - </init-param> - --> - <load-on-startup>0</load-on-startup> - </servlet> - - <servlet-mapping> - <servlet-name>jsp</servlet-name> - <url-pattern>*.jsp</url-pattern> - <url-pattern>*.jspf</url-pattern> - <url-pattern>*.jspx</url-pattern> - <url-pattern>*.xsp</url-pattern> - <url-pattern>*.JSP</url-pattern> - <url-pattern>*.JSPF</url-pattern> - <url-pattern>*.JSPX</url-pattern> - <url-pattern>*.XSP</url-pattern> - </servlet-mapping> - - <!-- ==================================================================== --> - <!-- Dynamic Servlet Invoker. --> - <!-- This servlet invokes anonymous servlets that have not been defined --> - <!-- in the web.xml or by other means. The first element of the pathInfo --> - <!-- of a request passed to the envoker is treated as a servlet name for --> - <!-- an existing servlet, or as a class name of a new servlet. --> - <!-- This servlet is normally mapped to /servlet/* --> - <!-- This servlet support the following initParams: --> - <!-- --> - <!-- nonContextServlets If false, the invoker can only load --> - <!-- servlets from the contexts classloader. --> - <!-- This is false by default and setting this --> - <!-- to true may have security implications. --> - <!-- --> - <!-- verbose If true, log dynamic loads --> - <!-- --> - <!-- * All other parameters are copied to the --> - <!-- each dynamic servlet as init parameters --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- - Uncomment for dynamic invocation <servlet> <servlet-name>invoker</servlet-name> <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class> <init-param> <param-name>verbose</param-name> - <param-value>false</param-value> </init-param> <init-param> <param-name>nonContextServlets</param-name> <param-value>false</param-value> </init-param> <init-param> - <param-name>dynamicParam</param-name> <param-value>anyValue</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>invoker</servlet-name> - <url-pattern>/servlet/*</url-pattern> </servlet-mapping> - --> - - - - <!-- ==================================================================== --> - <session-config> - <session-timeout>30</session-timeout> - </session-config> - - <!-- ==================================================================== --> - <!-- Default MIME mappings --> - <!-- The default MIME mappings are provided by the mime.properties --> - <!-- resource in the org.eclipse.jetty.server.jar file. Additional or modified --> - <!-- mappings may be specified here --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- UNCOMMENT TO ACTIVATE - <mime-mapping> - <extension>mysuffix</extension> - <mime-type>mymime/type</mime-type> - </mime-mapping> - --> - - <!-- ==================================================================== --> - <welcome-file-list> - <welcome-file>index.html</welcome-file> - <welcome-file>index.htm</welcome-file> - <welcome-file>index.jsp</welcome-file> - </welcome-file-list> - - <!-- ==================================================================== --> - <locale-encoding-mapping-list> - <locale-encoding-mapping> - <locale>ar</locale> - <encoding>ISO-8859-6</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>be</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>bg</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ca</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>cs</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>da</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>de</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>el</locale> - <encoding>ISO-8859-7</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>en</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>es</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>et</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>fi</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>fr</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>hr</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>hu</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>is</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>it</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>iw</locale> - <encoding>ISO-8859-8</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ja</locale> - <encoding>Shift_JIS</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ko</locale> - <encoding>EUC-KR</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>lt</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>lv</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>mk</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>nl</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>no</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>pl</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>pt</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ro</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>ru</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sh</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sk</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sl</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sq</locale> - <encoding>ISO-8859-2</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sr</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>sv</locale> - <encoding>ISO-8859-1</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>tr</locale> - <encoding>ISO-8859-9</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>uk</locale> - <encoding>ISO-8859-5</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>zh</locale> - <encoding>GB2312</encoding> - </locale-encoding-mapping> - <locale-encoding-mapping> - <locale>zh_TW</locale> - <encoding>Big5</encoding> - </locale-encoding-mapping> - </locale-encoding-mapping-list> - - <security-constraint> - <web-resource-collection> - <web-resource-name>Disable TRACE</web-resource-name> - <url-pattern>/</url-pattern> - <http-method>TRACE</http-method> - </web-resource-collection> - <auth-constraint/> - </security-constraint> - -</web-app> - diff --git a/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java b/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java index e2891a827d2..b1768c451df 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/GenerateBootstrapIndex.java @@ -84,7 +84,7 @@ public final class GenerateBootstrapIndex { return libs; } - private static final String[] IGNORE = {"jtds", "mysql", "postgresql", "jruby", "jfreechart", "eastwood", "jetty"}; + private static final String[] IGNORE = {"jtds", "mysql", "postgresql", "jruby", "jfreechart", "eastwood"}; /** * Dirty hack to disable downloading for certain files. diff --git a/sonar-server/src/main/webapp/META-INF/context.xml b/sonar-server/src/main/webapp/META-INF/context.xml index 389b9f408d1..b2c70d32f0f 100644 --- a/sonar-server/src/main/webapp/META-INF/context.xml +++ b/sonar-server/src/main/webapp/META-INF/context.xml @@ -1,3 +1,4 @@ -<Context antiJARLocking="true" antiResourceLocking="true" useHttpOnly="true"> - <ResourceLink name="jdbc/sonar" global="jdbc/sonar" type="javax.sql.DataSource" /> -</Context>
\ No newline at end of file +<Context antiJARLocking="true" antiResourceLocking="true" useHttpOnly="true" reloadable="false" processTlds="false" + unpackWAR="false" useNaming="false" xmlValidation="false" xmlNamespaceAware="false" tldValidation="false" + tldNamespaceAware="false"> +</Context> diff --git a/sonar-server/src/main/webapp/WEB-INF/web.xml b/sonar-server/src/main/webapp/WEB-INF/web.xml index 51e389f9639..69c75338ee5 100644 --- a/sonar-server/src/main/webapp/WEB-INF/web.xml +++ b/sonar-server/src/main/webapp/WEB-INF/web.xml @@ -2,7 +2,9 @@ <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" - id="SonarQube" version="3.0"> + id="SonarQube" + version="3.0" + metadata-complete="true"> <display-name>SonarQube</display-name> <context-param> @@ -46,31 +48,7 @@ <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> - <filter> - <!-- compatibility with servlet 2.5 containers like tomcat 6 --> - <filter-name>ContinuationFilter</filter-name> - <filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class> - </filter> - <filter> - <filter-name>GZIPFilter</filter-name> - <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class> - <init-param> - <param-name>minGzipSize</param-name> - <param-value>1024</param-value> - </init-param> - <init-param> - <param-name>bufferSize</param-name> - <param-value>16384</param-value> - </init-param> - </filter> - <filter-mapping> - <filter-name>ContinuationFilter</filter-name> - <url-pattern>/*</url-pattern> - </filter-mapping> - <filter-mapping> - <filter-name>GZIPFilter</filter-name> - <url-pattern>/*</url-pattern> - </filter-mapping> + <filter-mapping> <filter-name>DatabaseSessionFilter</filter-name> <url-pattern>/*</url-pattern> diff --git a/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java b/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java index 4bf0d40f0d2..77fff0b93e0 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/GenerateBootstrapIndexTest.java @@ -59,7 +59,6 @@ public class GenerateBootstrapIndexTest { assertThat(GenerateBootstrapIndex.isIgnored("jtds-1.2.4.jar")).isTrue(); assertThat(GenerateBootstrapIndex.isIgnored("jfreechart-1.0.9.jar")).isTrue(); assertThat(GenerateBootstrapIndex.isIgnored("eastwood-1.1.0.jar")).isTrue(); - assertThat(GenerateBootstrapIndex.isIgnored("jetty-util-6.1.24.jar")).isTrue(); assertThat(GenerateBootstrapIndex.isIgnored("jruby-complete-1.5.6.jar")).isTrue(); assertThat(GenerateBootstrapIndex.isIgnored("jruby-rack-1.0.5.jar")).isTrue(); } diff --git a/sonar-ws-client/pom.xml b/sonar-ws-client/pom.xml index 3d0d98ae3d6..a836636f58f 100644 --- a/sonar-ws-client/pom.xml +++ b/sonar-ws-client/pom.xml @@ -51,8 +51,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api</artifactId> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> <scope>test</scope> </dependency> <dependency> |