diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2019-08-08 12:28:41 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-08-14 20:21:12 +0200 |
commit | 4a557e2695c1ff7af001361dba25528f408bb833 (patch) | |
tree | ab30f994fb9f15bf399feb2551f76335a3006a4c /server/sonar-server | |
parent | 980b9f16b8a34364489d2ed3a8472f725eea4770 (diff) | |
download | sonarqube-4a557e2695c1ff7af001361dba25528f408bb833.tar.gz sonarqube-4a557e2695c1ff7af001361dba25528f408bb833.zip |
create sonar-webserver from sonar-server
contains the Web Server "executable", the Pico Container definition (to allow building it up from multiple modules) and Tomcat/JEE specific code
Diffstat (limited to 'server/sonar-server')
52 files changed, 6 insertions, 6031 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java b/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java deleted file mode 100644 index f323f975b49..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import com.google.common.base.Throwables; -import java.io.File; -import java.util.concurrent.CountDownLatch; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.startup.Tomcat; -import org.sonar.api.utils.log.Loggers; -import org.sonar.process.Props; - -import static org.sonar.core.util.FileUtils.deleteQuietly; -import static org.sonar.process.ProcessProperties.Property.PATH_TEMP; - -class EmbeddedTomcat { - - private final Props props; - private Tomcat tomcat = null; - private volatile StandardContext webappContext; - private final CountDownLatch stopLatch = new CountDownLatch(1); - - EmbeddedTomcat(Props props) { - this.props = props; - } - - void start() { - // '%2F' (slash /) and '%5C' (backslash \) are permitted as path delimiters in URLs - System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); - - System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true"); - // prevent Tomcat from shutting down our logging when stopping - System.setProperty("logbackDisableServletContainerInitializer", "true"); - - tomcat = new Tomcat(); - // Initialize directories - String basedir = tomcatBasedir().getAbsolutePath(); - tomcat.setBaseDir(basedir); - tomcat.getHost().setAppBase(basedir); - tomcat.getHost().setAutoDeploy(false); - tomcat.getHost().setCreateDirs(false); - tomcat.getHost().setDeployOnStartup(true); - new TomcatAccessLog().configure(tomcat, props); - TomcatConnectors.configure(tomcat, props); - webappContext = new TomcatContexts().configure(tomcat, props); - try { - tomcat.start(); - new TomcatStartupLogs(Loggers.get(getClass())).log(tomcat); - } catch (LifecycleException e) { - Loggers.get(EmbeddedTomcat.class).error("Fail to start web server", e); - Throwables.propagate(e); - } - } - - Status getStatus() { - if (webappContext == null) { - return Status.DOWN; - } - switch (webappContext.getState()) { - case NEW: - case INITIALIZING: - case INITIALIZED: - case STARTING_PREP: - case STARTING: - return Status.DOWN; - case STARTED: - return Status.UP; - default: - // problem, stopped or failed - return Status.FAILED; - } - } - - public enum Status { - DOWN, UP, FAILED - } - - private File tomcatBasedir() { - return new File(props.value(PATH_TEMP.getKey()), "tc"); - } - - void terminate() { - try { - if (tomcat.getServer().getState().isAvailable()) { - try { - tomcat.stop(); - tomcat.destroy(); - } catch (Exception e) { - Loggers.get(EmbeddedTomcat.class).warn("Failed to stop web server", e); - } - } - deleteQuietly(tomcatBasedir()); - } finally { - stopLatch.countDown(); - } - } - - void awaitTermination() { - try { - // calling tomcat.getServer().await() might block forever if stop fails for whatever reason - stopLatch.await(); - } catch (InterruptedException e) { - // quit - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/NullJarScanner.java b/server/sonar-server/src/main/java/org/sonar/server/app/NullJarScanner.java deleted file mode 100644 index ed2d54a9936..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/NullJarScanner.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import org.apache.tomcat.JarScanFilter; -import org.apache.tomcat.JarScanType; -import org.apache.tomcat.JarScanner; -import org.apache.tomcat.JarScannerCallback; - -import javax.servlet.ServletContext; - -/** - * Disable taglib and web-fragment.xml scanning of Tomcat. Should speed up startup. - */ - -class NullJarScanner implements JarScanner { - - @Override - public void scan(JarScanType jarScanType, ServletContext servletContext, JarScannerCallback jarScannerCallback) { - // doing nothing is fast! - } - - @Override - public JarScanFilter getJarScanFilter() { - return null; - } - - @Override - public void setJarScanFilter(JarScanFilter jarScanFilter) { - // no need to filter - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ProgrammaticLogbackValve.java b/server/sonar-server/src/main/java/org/sonar/server/app/ProgrammaticLogbackValve.java deleted file mode 100644 index f0d44b2da04..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/ProgrammaticLogbackValve.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import ch.qos.logback.access.tomcat.LogbackValve; -import ch.qos.logback.core.util.ExecutorServiceUtil; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleState; -import org.apache.commons.lang.reflect.FieldUtils; - -/** - * Implementation of {@link ch.qos.logback.access.tomcat.LogbackValve} that does not - * rely on the required file logback-access.xml. It allows to be configured - * programmatically. - */ -public class ProgrammaticLogbackValve extends LogbackValve { - - @Override - public synchronized void startInternal() throws LifecycleException { - try { - // direct coupling with LogbackValve implementation - FieldUtils.writeField(this, "scheduledExecutorService", ExecutorServiceUtil.newScheduledExecutorService(), true); - FieldUtils.writeField(this, "started", true, true); - setState(LifecycleState.STARTING); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatAccessLog.java b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatAccessLog.java deleted file mode 100644 index 1abf4a9b28d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatAccessLog.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import ch.qos.logback.access.PatternLayoutEncoder; -import ch.qos.logback.core.FileAppender; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.startup.Tomcat; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.process.logging.LogbackHelper; -import org.sonar.process.Props; - -class TomcatAccessLog { - - private static final String PROPERTY_ENABLE = "sonar.web.accessLogs.enable"; - private static final String PROPERTY_PATTERN = "sonar.web.accessLogs.pattern"; - private static final String DEFAULT_SQ_ACCESS_LOG_PATTERN = "%h %l %u [%t] \"%r\" %s %b \"%i{Referer}\" \"%i{User-Agent}\" \"%reqAttribute{ID}\""; - - void configure(Tomcat tomcat, Props props) { - tomcat.setSilent(true); - tomcat.getService().addLifecycleListener(new LifecycleLogger(Loggers.get(TomcatAccessLog.class))); - configureLogbackAccess(tomcat, props); - } - - private static void configureLogbackAccess(Tomcat tomcat, Props props) { - if (props.valueAsBoolean(PROPERTY_ENABLE, true)) { - ProgrammaticLogbackValve valve = new ProgrammaticLogbackValve(); - LogbackHelper helper = new LogbackHelper(); - LogbackHelper.RollingPolicy policy = helper.createRollingPolicy(valve, props, "access"); - FileAppender appender = policy.createAppender("ACCESS_LOG"); - PatternLayoutEncoder fileEncoder = new PatternLayoutEncoder(); - fileEncoder.setContext(valve); - fileEncoder.setPattern(props.value(PROPERTY_PATTERN, DEFAULT_SQ_ACCESS_LOG_PATTERN)); - fileEncoder.start(); - appender.setEncoder(fileEncoder); - appender.start(); - valve.addAppender(appender); - tomcat.getHost().getPipeline().addValve(valve); - } - } - - static class LifecycleLogger implements LifecycleListener { - private Logger logger; - - LifecycleLogger(Logger logger) { - this.logger = logger; - } - - @Override - public void lifecycleEvent(LifecycleEvent event) { - if ("after_start".equals(event.getType())) { - logger.debug("Tomcat is started"); - - } else if ("after_destroy".equals(event.getType())) { - logger.debug("Tomcat is stopped"); - } - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatConnectors.java b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatConnectors.java deleted file mode 100644 index e63c28cd312..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatConnectors.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import javax.annotation.Nullable; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.startup.Tomcat; -import org.sonar.process.Props; - -import static java.lang.String.format; - -/** - * Configuration of Tomcat connectors - */ -class TomcatConnectors { - - static final String HTTP_PROTOCOL = "HTTP/1.1"; - static final int MAX_HTTP_HEADER_SIZE_BYTES = 48 * 1024; - private static final int MAX_POST_SIZE = -1; - - private TomcatConnectors() { - // only static stuff - } - - static void configure(Tomcat tomcat, Props props) { - Connector httpConnector = newHttpConnector(props); - tomcat.getService().addConnector(httpConnector); - } - - private static Connector newHttpConnector(Props props) { - // Not named "sonar.web.http.port" to keep backward-compatibility - int port = props.valueAsInt("sonar.web.port", 9000); - if (port < 0) { - throw new IllegalStateException(format("HTTP port '%s' is invalid", port)); - } - - Connector connector = new Connector(HTTP_PROTOCOL); - connector.setURIEncoding("UTF-8"); - connector.setProperty("address", props.value("sonar.web.host", "0.0.0.0")); - connector.setProperty("socket.soReuseAddress", "true"); - // see https://tomcat.apache.org/tomcat-8.5-doc/config/http.html - connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}"); - configurePool(props, connector); - configureCompression(connector); - configureMaxHttpHeaderSize(connector); - connector.setPort(port); - connector.setMaxPostSize(MAX_POST_SIZE); - return connector; - } - - /** - * HTTP header must be at least 48kb to accommodate the authentication token used for - * negotiate protocol of windows authentication. - */ - private static void configureMaxHttpHeaderSize(Connector connector) { - setConnectorAttribute(connector, "maxHttpHeaderSize", MAX_HTTP_HEADER_SIZE_BYTES); - } - - private static void configurePool(Props props, Connector connector) { - connector.setProperty("acceptorThreadCount", String.valueOf(2)); - connector.setProperty("minSpareThreads", String.valueOf(props.valueAsInt("sonar.web.http.minThreads", 5))); - connector.setProperty("maxThreads", String.valueOf(props.valueAsInt("sonar.web.http.maxThreads", 50))); - connector.setProperty("acceptCount", String.valueOf(props.valueAsInt("sonar.web.http.acceptCount", 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"); - } - - private static void setConnectorAttribute(Connector c, String key, @Nullable Object value) { - if (value != null) { - c.setAttribute(key, value); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java deleted file mode 100644 index 81cf3a59b5d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import com.google.common.annotations.VisibleForTesting; -import java.io.File; -import java.io.IOException; -import java.util.Map; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.startup.Tomcat; -import org.apache.commons.io.FileUtils; -import org.sonar.api.utils.MessageException; -import org.sonar.process.Props; - -import static java.lang.String.format; -import static org.sonar.process.ProcessProperties.Property.PATH_DATA; -import static org.sonar.process.ProcessProperties.Property.PATH_HOME; - -/** - * Configures Tomcat contexts: - * <ul> - * <li>/deploy delivers the plugins required by analyzers. It maps directory ${sonar.path.data}/web/deploy.</li> - * <li>/ is the regular webapp</li> - * </ul> - */ -public class TomcatContexts { - - private static final String PROPERTY_CONTEXT = "sonar.web.context"; - private static final String WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR = "web/deploy"; - - private final Fs fs; - - public TomcatContexts() { - this.fs = new Fs(); - } - - @VisibleForTesting - TomcatContexts(Fs fs) { - this.fs = fs; - } - - public StandardContext configure(Tomcat tomcat, Props props) { - addStaticDir(tomcat, getContextPath(props) + "/deploy", new File(props.nonNullValueAsFile(PATH_DATA.getKey()), WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR)); - - StandardContext webapp = addContext(tomcat, getContextPath(props), webappDir(props)); - for (Map.Entry<Object, Object> entry : props.rawProperties().entrySet()) { - String key = entry.getKey().toString(); - webapp.addParameter(key, entry.getValue().toString()); - } - return webapp; - } - - static String getContextPath(Props props) { - String context = props.value(PROPERTY_CONTEXT, ""); - if ("/".equals(context)) { - context = ""; - } else if (!"".equals(context) && context != null && !context.startsWith("/")) { - throw MessageException.of(format("Value of '%s' must start with a forward slash: '%s'", PROPERTY_CONTEXT, context)); - } - return context; - } - - @VisibleForTesting - StandardContext addStaticDir(Tomcat tomcat, String contextPath, File dir) { - try { - fs.createOrCleanupDir(dir); - } catch (IOException e) { - throw new IllegalStateException(format("Fail to create or clean-up directory %s", dir.getAbsolutePath()), e); - } - - return addContext(tomcat, contextPath, dir); - } - - private static StandardContext addContext(Tomcat tomcat, String contextPath, File dir) { - try { - StandardContext context = (StandardContext) tomcat.addWebapp(contextPath, dir.getAbsolutePath()); - context.setClearReferencesHttpClientKeepAliveThread(false); - context.setClearReferencesStopThreads(false); - context.setClearReferencesStopTimerThreads(false); - context.setClearReferencesStopTimerThreads(false); - context.setAntiResourceLocking(false); - context.setReloadable(false); - context.setUseHttpOnly(true); - context.setTldValidation(false); - context.setXmlValidation(false); - context.setXmlNamespaceAware(false); - context.setUseNaming(false); - context.setDelegate(true); - context.setJarScanner(new NullJarScanner()); - context.setAllowCasualMultipartParsing(true); - context.setCookies(false); - // disable JSP and WebSocket support - context.setContainerSciFilter("org.apache.tomcat.websocket.server.WsSci|org.apache.jasper.servlet.JasperInitializer"); - return context; - } catch (Exception e) { - throw new IllegalStateException("Fail to configure webapp from " + dir, e); - } - } - - private static File webappDir(Props props) { - return new File(props.value(PATH_HOME.getKey()), "web"); - } - - static class Fs { - void createOrCleanupDir(File dir) throws IOException { - FileUtils.forceMkdir(dir); - org.sonar.core.util.FileUtils.cleanDirectory(dir); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatStartupLogs.java b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatStartupLogs.java deleted file mode 100644 index e9eb5307e90..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatStartupLogs.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import org.apache.catalina.connector.Connector; -import org.apache.catalina.startup.Tomcat; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.utils.log.Logger; - -class TomcatStartupLogs { - - private final Logger log; - - TomcatStartupLogs(Logger log) { - this.log = log; - } - - void log(Tomcat tomcat) { - Connector[] connectors = tomcat.getService().findConnectors(); - for (Connector connector : connectors) { - if (StringUtils.equalsIgnoreCase(connector.getScheme(), "http")) { - logHttp(connector); - } else { - throw new IllegalArgumentException("Unsupported connector: " + connector); - } - } - } - - private void logHttp(Connector connector) { - log.info(String.format("HTTP connector enabled on port %d", connector.getPort())); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/WebServer.java b/server/sonar-server/src/main/java/org/sonar/server/app/WebServer.java deleted file mode 100644 index cfb5493bdbb..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/WebServer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import com.google.common.collect.ImmutableMap; -import java.io.File; -import org.slf4j.LoggerFactory; -import org.sonar.process.MinimumViableSystem; -import org.sonar.process.Monitored; -import org.sonar.process.ProcessEntryPoint; -import org.sonar.process.ProcessId; -import org.sonar.process.Props; -import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; - -public class WebServer implements Monitored { - public static final String PROPERTY_SHARED_PATH = "process.sharedDir"; - - private final File sharedDir; - private final EmbeddedTomcat tomcat; - - WebServer(Props props) { - new MinimumViableSystem() - .checkWritableTempDir() - .checkRequiredJavaOptions(ImmutableMap.of("file.encoding", "UTF-8")); - this.sharedDir = getSharedDir(props); - this.tomcat = new EmbeddedTomcat(props); - } - - private static File getSharedDir(Props props) { - return props.nonNullValueAsFile(PROPERTY_SHARED_PATH); - } - - @Override - public void start() { - tomcat.start(); - } - - @Override - public Status getStatus() { - switch (tomcat.getStatus()) { - case DOWN: - return Status.DOWN; - case UP: - return isOperational() ? Status.OPERATIONAL : Status.UP; - case FAILED: - default: - return Status.FAILED; - } - } - - private boolean isOperational() { - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(sharedDir, ProcessId.WEB_SERVER.getIpcIndex())) { - return processCommands.isOperational(); - } - } - - @Override - public void stop() { - // hard stop is as graceful as stop for the WebServer - hardStop(); - LoggerFactory.getLogger(WebServer.class).info("WebServer stopped"); - } - - @Override - public void hardStop() { - tomcat.terminate(); - } - - @Override - public void awaitStop() { - tomcat.awaitTermination(); - } - - /** - * Can't be started as is. Needs to be bootstrapped by sonar-application - */ - public static void main(String[] args) { - ProcessEntryPoint entryPoint = ProcessEntryPoint.createForArguments(args); - Props props = entryPoint.getProps(); - new WebServerProcessLogging().configure(props); - WebServer server = new WebServer(props); - entryPoint.launch(server); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/app/package-info.java deleted file mode 100644 index 358bed4fd65..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/app/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 121d08f774a..22f3e451a97 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -19,406 +19,16 @@ */ package org.sonar.server.platform; -import com.google.common.collect.Lists; -import java.util.Collection; -import java.util.List; -import java.util.Properties; -import java.util.function.Supplier; -import javax.annotation.Nullable; -import javax.servlet.ServletContext; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; import org.sonar.core.platform.ComponentContainer; -import org.sonar.server.app.ProcessCommandWrapper; -import org.sonar.server.platform.db.migration.version.DatabaseVersion; -import org.sonar.server.platform.platformlevel.PlatformLevel; -import org.sonar.server.platform.platformlevel.PlatformLevel1; -import org.sonar.server.platform.platformlevel.PlatformLevel2; -import org.sonar.server.platform.platformlevel.PlatformLevel3; -import org.sonar.server.platform.platformlevel.PlatformLevel4; -import org.sonar.server.platform.platformlevel.PlatformLevelSafeMode; -import org.sonar.server.platform.platformlevel.PlatformLevelStartup; -/** - * @since 2.2 - */ -public class Platform { - - private static final Logger LOGGER = Loggers.get(Platform.class); - - private static final Platform INSTANCE = new Platform(); - - private final Supplier<AutoStarter> autoStarterSupplier; - private AutoStarter autoStarter = null; - private Properties properties; - private ServletContext servletContext; - private PlatformLevel level1; - private PlatformLevel level2; - private PlatformLevel levelSafeMode; - private PlatformLevel level3; - private PlatformLevel level4; - private PlatformLevel currentLevel; - private boolean dbConnected = false; - private boolean started = false; - private final List<Object> level4AddedComponents = Lists.newArrayList(); - private final Profiler profiler = Profiler.createIfTrace(Loggers.get(Platform.class)); - - private Platform() { - this.autoStarterSupplier = () -> { - ProcessCommandWrapper processCommandWrapper = getContainer().getComponentByType(ProcessCommandWrapper.class); - return new AsynchronousAutoStarter(processCommandWrapper); - }; - } - - protected Platform(Supplier<AutoStarter> autoStarterSupplier) { - this.autoStarterSupplier = autoStarterSupplier; - } - - public static Platform getInstance() { - return INSTANCE; - } - - public void init(Properties properties, ServletContext servletContext) { - this.properties = properties; - this.servletContext = servletContext; - if (!dbConnected) { - startLevel1Container(); - startLevel2Container(); - currentLevel = level2; - dbConnected = true; - } - } - - // Platform is injected in Pico, so do not rename this method "start" - public void doStart() { - doStart(Startup.ALL); - } - - protected void doStart(Startup startup) { - if (started && !isInSafeMode()) { - return; - } - - boolean dbRequiredMigration = dbRequiresMigration(); - startSafeModeContainer(); - currentLevel = levelSafeMode; - started = true; - - // if AutoDbMigration kicked in or no DB migration was required, startup can be resumed in another thread - if (dbRequiresMigration()) { - LOGGER.info("Database needs to be migrated. Please refer to https://docs.sonarqube.org/latest/setup/upgrading"); - } else { - this.autoStarter = autoStarterSupplier.get(); - this.autoStarter.execute(new AutoStarterRunnable(autoStarter) { - @Override - public void doRun() { - if (dbRequiredMigration) { - LOGGER.info("Database has been automatically updated"); - } - runIfNotAborted(Platform.this::startLevel34Containers); - - runIfNotAborted(() -> executeStartupTasks(startup)); - // switch current container last to avoid giving access to a partially initialized container - runIfNotAborted(() -> { - currentLevel = level4; - LOGGER.info("WebServer is operational"); - }); - - // stop safemode container if it existed - runIfNotAborted(Platform.this::stopSafeModeContainer); - } - }); - } - } - - private boolean dbRequiresMigration() { - return getDatabaseStatus() != DatabaseVersion.Status.UP_TO_DATE; - } +public interface Platform { + void doStart(); - public boolean isStarted() { - return status() == Status.UP; - } - - public boolean isInSafeMode() { - return status() == Status.SAFEMODE; - } - - public Status status() { - if (!started) { - return Status.BOOTING; - } - PlatformLevel current = this.currentLevel; - PlatformLevel levelSafe = this.levelSafeMode; - if (levelSafe != null && current == levelSafe) { - return isRunning(this.autoStarter) ? Status.STARTING : Status.SAFEMODE; - } - if (current == level4) { - return Status.UP; - } - return Status.BOOTING; - } - - private static boolean isRunning(@Nullable AutoStarter autoStarter) { - return autoStarter != null && autoStarter.isRunning(); - } - - /** - * Starts level 1 - */ - private void startLevel1Container() { - level1 = start(new PlatformLevel1(this, properties, servletContext)); - } - - /** - * Starts level 2 - */ - private void startLevel2Container() { - level2 = start(new PlatformLevel2(level1)); - } + Status status(); - /** - * Starts level 3 and 4 - */ - private void startLevel34Containers() { - level3 = start(new PlatformLevel3(level2)); - level4 = start(new PlatformLevel4(level3, level4AddedComponents)); - } - - public void executeStartupTasks() { - executeStartupTasks(Startup.ALL); - } + ComponentContainer getContainer(); - private void executeStartupTasks(Startup startup) { - if (startup.ordinal() >= Startup.ALL.ordinal()) { - new PlatformLevelStartup(level4) - .configure() - .start() - .stop() - .destroy(); - } - } - - private void startSafeModeContainer() { - levelSafeMode = start(new PlatformLevelSafeMode(level2)); - } - - private PlatformLevel start(PlatformLevel platformLevel) { - profiler.start(); - platformLevel.configure(); - profiler.stopTrace(String.format("%s configured", platformLevel.getName())); - profiler.start(); - platformLevel.start(); - profiler.stopTrace(String.format("%s started", platformLevel.getName())); - - return platformLevel; - } - - /** - * Stops level 1 - */ - private void stopLevel1Container() { - if (level1 != null) { - level1.stop(); - level1 = null; - } - } - - /** - * Stops level 2, 3 and 4 containers cleanly if they exists. - * Call this method before {@link #startLevel1Container()} to avoid duplicate attempt to stop safemode container - * components (since calling stop on a container calls stop on its children too, see - * {@link ComponentContainer#stopComponents()}). - */ - private void stopLevel234Containers() { - if (level2 != null) { - level2.stop(); - level2 = null; - level3 = null; - level4 = null; - } - } - - /** - * Stops safemode container cleanly if it exists. - * Call this method before {@link #stopLevel234Containers()} and {@link #stopLevel1Container()} to avoid duplicate - * attempt to stop safemode container components (since calling stop on a container calls stops on its children too, - * see {@link ComponentContainer#stopComponents()}). - */ - private void stopSafeModeContainer() { - if (levelSafeMode != null) { - levelSafeMode.stop(); - levelSafeMode = null; - } - } - - private DatabaseVersion.Status getDatabaseStatus() { - DatabaseVersion version = getContainer().getComponentByType(DatabaseVersion.class); - return version.getStatus(); - } - - // Do not rename "stop" - public void doStop() { - try { - stopAutoStarter(); - stopSafeModeContainer(); - stopLevel234Containers(); - stopLevel1Container(); - currentLevel = null; - dbConnected = false; - started = false; - } catch (Exception e) { - LOGGER.error("Fail to stop server - ignored", e); - } - } - - private void stopAutoStarter() { - if (autoStarter != null) { - autoStarter.abort(); - autoStarter = null; - } - } - - public void addComponents(Collection<?> components) { - level4AddedComponents.addAll(components); - } - - public ComponentContainer getContainer() { - return currentLevel.getContainer(); - } - - public Object getComponent(Object key) { - return getContainer().getComponentByKey(key); - } - - public enum Status { + enum Status { BOOTING, SAFEMODE, STARTING, UP } - - public enum Startup { - NO_STARTUP_TASKS, ALL - } - - public interface AutoStarter { - /** - * Let the autostarted execute the provided code. - */ - void execute(Runnable startCode); - - /** - * This method is called by executed start code (see {@link #execute(Runnable)} has finished with a failure. - */ - void failure(Throwable t); - - /** - * This method is called by executed start code (see {@link #execute(Runnable)} has finished successfully. - */ - void success(); - - /** - * Indicates whether the AutoStarter is running. - */ - boolean isRunning(); - - /** - * Requests the startcode (ie. the argument of {@link #execute(Runnable)}) aborts its processing (if it supports it). - */ - void abort(); - - /** - * Indicates whether {@link #abort()} was invoked. - * <p> - * This method can be used by the start code to check whether it should proceed running or stop. - * </p> - */ - boolean isAborting(); - - /** - * Called when abortion is complete. - * <p> - * Start code support abortion should call this method once is done processing and if it stopped on abortion. - * </p> - */ - void aborted(); - } - - private abstract static class AutoStarterRunnable implements Runnable { - private final AutoStarter autoStarter; - - AutoStarterRunnable(AutoStarter autoStarter) { - this.autoStarter = autoStarter; - } - - @Override - public void run() { - try { - doRun(); - } catch (Throwable t) { - autoStarter.failure(t); - } finally { - if (autoStarter.isAborting()) { - autoStarter.aborted(); - } else { - autoStarter.success(); - } - } - } - - abstract void doRun(); - - void runIfNotAborted(Runnable r) { - if (!autoStarter.isAborting()) { - r.run(); - } - } - } - - private static final class AsynchronousAutoStarter implements AutoStarter { - private final ProcessCommandWrapper processCommandWrapper; - private boolean running = true; - private boolean abort = false; - - private AsynchronousAutoStarter(ProcessCommandWrapper processCommandWrapper) { - this.processCommandWrapper = processCommandWrapper; - } - - @Override - public void execute(Runnable startCode) { - new Thread(startCode, "SQ starter").start(); - } - - @Override - public void failure(Throwable t) { - LOGGER.error("Background initialization failed. Stopping SonarQube", t); - processCommandWrapper.requestHardStop(); - this.running = false; - } - - @Override - public void success() { - LOGGER.debug("Background initialization of SonarQube done"); - this.running = false; - } - - @Override - public void aborted() { - LOGGER.debug("Background initialization of SonarQube aborted"); - this.running = false; - } - - @Override - public boolean isRunning() { - return running; - } - - @Override - public void abort() { - this.abort = true; - } - - @Override - public boolean isAborting() { - return this.abort; - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel.java deleted file mode 100644 index 68faf71cfda..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.core.platform.Module; -import org.sonar.server.platform.WebServer; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Objects.requireNonNull; - -public abstract class PlatformLevel { - private final String name; - @Nullable - private final PlatformLevel parent; - private final ComponentContainer container; - private AddIfStartupLeader addIfStartupLeader; - private AddIfCluster addIfCluster; - private AddIfStandalone addIfStandalone; - - public PlatformLevel(String name) { - this.name = name; - this.parent = null; - this.container = createContainer(null); - } - - public PlatformLevel(String name, @Nonnull PlatformLevel parent) { - this.name = checkNotNull(name); - this.parent = checkNotNull(parent); - this.container = createContainer(parent.container); - } - - public ComponentContainer getContainer() { - return container; - } - - public String getName() { - return name; - } - - /** - * Intended to be override by subclasses if needed - */ - protected ComponentContainer createContainer(@Nullable ComponentContainer parent) { - if (parent == null) { - return new ComponentContainer(); - } - return parent.createChild(); - } - - public PlatformLevel configure() { - configureLevel(); - - List<Module> modules = container.getComponentsByType(Module.class); - for (Module module : modules) { - module.configure(container); - } - - return this; - } - - protected abstract void configureLevel(); - - /** - * Intended to be override by subclasses if needed - */ - public PlatformLevel start() { - container.startComponents(); - - return this; - } - - /** - * Intended to be override by subclasses if needed - */ - public PlatformLevel stop() { - container.stopComponents(); - - return this; - } - - /** - * Intended to be override by subclasses if needed - */ - public PlatformLevel destroy() { - if (parent != null) { - parent.container.removeChild(container); - } - return this; - } - - protected <T> T get(Class<T> tClass) { - return requireNonNull(container.getComponentByType(tClass)); - } - - protected <T> List<T> getAll(Class<T> tClass) { - return container.getComponentsByType(tClass); - } - - protected <T> Optional<T> getOptional(Class<T> tClass) { - return Optional.ofNullable(container.getComponentByType(tClass)); - } - - protected void add(Object... objects) { - for (Object object : objects) { - if (object != null) { - container.addComponent(object, true); - } - } - } - - /** - * Add a component to container only if the web server is startup leader. - * - * @throws IllegalStateException if called from PlatformLevel1, when cluster settings are not loaded - */ - AddIfStartupLeader addIfStartupLeader(Object... objects) { - if (addIfStartupLeader == null) { - this.addIfStartupLeader = new AddIfStartupLeader(getWebServer().isStartupLeader()); - } - addIfStartupLeader.ifAdd(objects); - return addIfStartupLeader; - } - - /** - * Add a component to container only if clustering is enabled. - * - * @throws IllegalStateException if called from PlatformLevel1, when cluster settings are not loaded - */ - AddIfCluster addIfCluster(Object... objects) { - if (addIfCluster == null) { - addIfCluster = new AddIfCluster(!getWebServer().isStandalone()); - } - addIfCluster.ifAdd(objects); - return addIfCluster; - } - - /** - * Add a component to container only if this is a standalone instance, without clustering. - * - * @throws IllegalStateException if called from PlatformLevel1, when cluster settings are not loaded - */ - AddIfStandalone addIfStandalone(Object... objects) { - if (addIfStandalone == null) { - addIfStandalone = new AddIfStandalone(getWebServer().isStandalone()); - } - addIfStandalone.ifAdd(objects); - return addIfStandalone; - } - - private WebServer getWebServer() { - return getOptional(WebServer.class) - .orElseThrow(() -> new IllegalStateException("WebServer not available in Pico yet")); - } - - private abstract class AddIf { - private final boolean condition; - - private AddIf(boolean condition) { - this.condition = condition; - } - - public void ifAdd(Object... objects) { - if (condition) { - PlatformLevel.this.add(objects); - } - } - - public void otherwiseAdd(Object... objects) { - if (!condition) { - PlatformLevel.this.add(objects); - } - } - } - - public final class AddIfStartupLeader extends AddIf { - private AddIfStartupLeader(boolean condition) { - super(condition); - } - } - - public final class AddIfCluster extends AddIf { - private AddIfCluster(boolean condition) { - super(condition); - } - } - - public final class AddIfStandalone extends AddIf { - private AddIfStandalone(boolean condition) { - super(condition); - } - } - - protected void addAll(Collection<?> objects) { - add(objects.toArray(new Object[objects.size()])); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java deleted file mode 100644 index 184fd922bc3..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.time.Clock; -import java.util.Properties; -import javax.annotation.Nullable; -import org.sonar.api.SonarEdition; -import org.sonar.api.SonarQubeSide; -import org.sonar.api.SonarQubeVersion; -import org.sonar.api.internal.MetadataLoader; -import org.sonar.api.internal.SonarRuntimeImpl; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.Version; -import org.sonar.server.util.TempFolderCleaner; -import org.sonar.core.config.CorePropertyDefinitions; -import org.sonar.core.extension.CoreExtensionRepositoryImpl; -import org.sonar.core.extension.CoreExtensionsLoader; -import org.sonar.core.util.UuidFactoryImpl; -import org.sonar.db.DBSessionsImpl; -import org.sonar.db.DaoModule; -import org.sonar.db.DbClient; -import org.sonar.db.DefaultDatabase; -import org.sonar.db.MyBatis; -import org.sonar.db.purge.PurgeProfiler; -import org.sonar.process.NetworkUtilsImpl; -import org.sonar.process.logging.LogbackHelper; -import org.sonar.server.app.ProcessCommandWrapperImpl; -import org.sonar.server.app.RestartFlagHolderImpl; -import org.sonar.server.app.WebServerProcessLogging; -import org.sonar.server.config.ConfigurationProvider; -import org.sonar.server.es.EsModule; -import org.sonar.server.issue.index.IssueIndex; -import org.sonar.server.permission.index.WebAuthorizationTypeSupport; -import org.sonar.server.platform.LogServerVersion; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.ServerFileSystemImpl; -import org.sonar.server.platform.TempFolderProvider; -import org.sonar.server.platform.UrlSettings; -import org.sonar.server.platform.WebCoreExtensionsInstaller; -import org.sonar.server.platform.WebServerImpl; -import org.sonar.server.platform.db.EmbeddedDatabaseFactory; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.setting.ThreadLocalSettings; -import org.sonar.server.user.SystemPasscodeImpl; -import org.sonar.server.user.ThreadLocalUserSession; -import org.sonar.server.util.GlobalLockManager; -import org.sonar.server.util.OkHttpClientProvider; - -import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; -import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; - -public class PlatformLevel1 extends PlatformLevel { - private final Platform platform; - private final Properties properties; - @Nullable - private final Object[] extraRootComponents; - - public PlatformLevel1(Platform platform, Properties properties, Object... extraRootComponents) { - super("level1"); - this.platform = platform; - this.properties = properties; - this.extraRootComponents = extraRootComponents; - } - - @Override - public void configureLevel() { - add(platform, properties); - addExtraRootComponents(); - Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE); - SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE); - - add( - new SonarQubeVersion(apiVersion), - SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SERVER, edition), - ThreadLocalSettings.class, - new ConfigurationProvider(), - LogServerVersion.class, - ProcessCommandWrapperImpl.class, - RestartFlagHolderImpl.class, - UuidFactoryImpl.INSTANCE, - NetworkUtilsImpl.INSTANCE, - UrlSettings.class, - EmbeddedDatabaseFactory.class, - LogbackHelper.class, - WebServerProcessLogging.class, - DefaultDatabase.class, - MyBatis.class, - PurgeProfiler.class, - ServerFileSystemImpl.class, - TempFolderCleaner.class, - new TempFolderProvider(), - System2.INSTANCE, - Clock.systemDefaultZone(), - - // user session - ThreadLocalUserSession.class, - SystemPasscodeImpl.class, - - // DB - DBSessionsImpl.class, - DbClient.class, - DaoModule.class, - - // Elasticsearch - WebAuthorizationTypeSupport.class, - EsModule.class, - - // rules/qprofiles - RuleIndex.class, - - // issues - IssueIndex.class, - - GlobalLockManager.class, - - new OkHttpClientProvider(), - - CoreExtensionRepositoryImpl.class, - CoreExtensionsLoader.class, - WebCoreExtensionsInstaller.class); - addAll(CorePropertyDefinitions.all()); - - // cluster - add(WebServerImpl.class); - } - - private void addExtraRootComponents() { - if (this.extraRootComponents != null) { - for (Object extraRootComponent : this.extraRootComponents) { - add(extraRootComponent); - } - } - } - - @Override - public PlatformLevel start() { - get(CoreExtensionsLoader.class) - .load(); - get(WebCoreExtensionsInstaller.class) - .install(getContainer(), hasPlatformLevel(1), noAdditionalSideFilter()); - - return super.start(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java deleted file mode 100644 index 26da9589616..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import org.sonar.api.utils.Durations; -import org.sonar.core.extension.CoreExtensionsInstaller; -import org.sonar.core.i18n.RuleI18nManager; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.core.platform.PluginClassloaderFactory; -import org.sonar.core.platform.PluginLoader; -import org.sonar.server.es.MigrationEsClientImpl; -import org.sonar.server.l18n.ServerI18n; -import org.sonar.server.platform.DatabaseServerCompatibility; -import org.sonar.server.platform.DefaultServerUpgradeStatus; -import org.sonar.server.platform.OfficialDistribution; -import org.sonar.server.platform.StartupMetadataProvider; -import org.sonar.server.platform.WebCoreExtensionsInstaller; -import org.sonar.server.platform.db.CheckDatabaseCharsetAtStartup; -import org.sonar.server.platform.db.migration.DatabaseMigrationExecutorServiceImpl; -import org.sonar.server.platform.db.migration.DatabaseMigrationStateImpl; -import org.sonar.server.platform.db.migration.MigrationConfigurationModule; -import org.sonar.server.platform.db.migration.charset.DatabaseCharsetChecker; -import org.sonar.server.platform.db.migration.history.MigrationHistoryTable; -import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl; -import org.sonar.server.platform.db.migration.version.DatabaseVersion; -import org.sonar.server.platform.web.WebPagesCache; -import org.sonar.server.plugins.InstalledPluginReferentialFactory; -import org.sonar.server.plugins.PluginFileSystem; -import org.sonar.server.plugins.ServerPluginJarExploder; -import org.sonar.server.plugins.ServerPluginRepository; -import org.sonar.server.plugins.WebServerExtensionInstaller; - -import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; -import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; - -public class PlatformLevel2 extends PlatformLevel { - public PlatformLevel2(PlatformLevel parent) { - super("level2", parent); - } - - @Override - protected void configureLevel() { - add( - MigrationConfigurationModule.class, - DatabaseVersion.class, - DatabaseServerCompatibility.class, - MigrationEsClientImpl.class, - - new StartupMetadataProvider(), - DefaultServerUpgradeStatus.class, - Durations.class, - - // index.html cache - WebPagesCache.class, - - // plugins - ServerPluginRepository.class, - ServerPluginJarExploder.class, - PluginLoader.class, - PluginFileSystem.class, - PluginClassloaderFactory.class, - InstalledPluginReferentialFactory.class, - WebServerExtensionInstaller.class, - - // depends on plugins - ServerI18n.class, - RuleI18nManager.class, - - OfficialDistribution.class); - - // Migration state must be kept at level2 to survive moving in and then out of safe mode - // ExecutorService must be kept at level2 because stopping it when stopping safe mode level causes error making SQ fail - add( - MigrationHistoryTableImpl.class, - DatabaseMigrationStateImpl.class, - DatabaseMigrationExecutorServiceImpl.class); - - addIfStartupLeader( - DatabaseCharsetChecker.class, - CheckDatabaseCharsetAtStartup.class); - } - - @Override - public PlatformLevel start() { - // ensuring the HistoryTable exists must be the first thing done when this level is started - getOptional(MigrationHistoryTable.class).ifPresent(MigrationHistoryTable::start); - - ComponentContainer container = getContainer(); - CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); - coreExtensionsInstaller.install(container, hasPlatformLevel(2), noAdditionalSideFilter()); - - return super.start(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java deleted file mode 100644 index 2bab0b816c2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import org.sonar.api.utils.UriReader; -import org.sonar.core.extension.CoreExtensionsInstaller; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.core.util.DefaultHttpDownloader; -import org.sonar.server.async.AsyncExecutionModule; -import org.sonar.server.organization.DefaultOrganizationProviderImpl; -import org.sonar.server.organization.OrganizationFlagsImpl; -import org.sonar.server.platform.ServerImpl; -import org.sonar.server.platform.StartupMetadataPersister; -import org.sonar.server.platform.WebCoreExtensionsInstaller; -import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl; -import org.sonar.server.platform.serverid.ServerIdModule; -import org.sonar.server.setting.DatabaseSettingLoader; -import org.sonar.server.setting.DatabaseSettingsEnabler; - -import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; -import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; - -public class PlatformLevel3 extends PlatformLevel { - public PlatformLevel3(PlatformLevel parent) { - super("level3", parent); - } - - @Override - protected void configureLevel() { - addIfStartupLeader(StartupMetadataPersister.class); - add( - NoopDatabaseMigrationImpl.class, - ServerIdModule.class, - ServerImpl.class, - DatabaseSettingLoader.class, - DatabaseSettingsEnabler.class, - UriReader.class, - DefaultHttpDownloader.class, - DefaultOrganizationProviderImpl.class, - OrganizationFlagsImpl.class, - AsyncExecutionModule.class); - } - - @Override - public PlatformLevel start() { - ComponentContainer container = getContainer(); - CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); - coreExtensionsInstaller.install(container, hasPlatformLevel(3), noAdditionalSideFilter()); - - return super.start(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java deleted file mode 100644 index 8e850fa4449..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.util.List; -import org.sonar.api.profiles.AnnotationProfileParser; -import org.sonar.api.profiles.XMLProfileParser; -import org.sonar.api.profiles.XMLProfileSerializer; -import org.sonar.api.resources.Languages; -import org.sonar.api.resources.ResourceTypes; -import org.sonar.api.rules.AnnotationRuleParser; -import org.sonar.api.rules.XMLRuleParser; -import org.sonar.api.server.rule.RulesDefinitionXmlLoader; -import org.sonar.ce.task.projectanalysis.notification.ReportAnalysisFailureNotificationModule; -import org.sonar.core.component.DefaultResourceTypes; -import org.sonar.core.extension.CoreExtensionsInstaller; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.core.platform.PlatformEditionProvider; -import org.sonar.server.authentication.AuthenticationModule; -import org.sonar.server.authentication.LogOAuthWarning; -import org.sonar.server.badge.ws.ProjectBadgesWsModule; -import org.sonar.server.batch.BatchWsModule; -import org.sonar.server.branch.BranchFeatureProxyImpl; -import org.sonar.server.branch.pr.ws.PullRequestWsModule; -import org.sonar.server.branch.ws.BranchWsModule; -import org.sonar.server.ce.CeModule; -import org.sonar.server.ce.ws.CeWsModule; -import org.sonar.server.component.ComponentCleanerService; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.component.ComponentService; -import org.sonar.server.component.ComponentUpdater; -import org.sonar.server.component.index.ComponentIndex; -import org.sonar.server.component.index.ComponentIndexDefinition; -import org.sonar.server.component.index.ComponentIndexer; -import org.sonar.server.component.ws.ComponentViewerJsonWriter; -import org.sonar.server.component.ws.ComponentsWsModule; -import org.sonar.server.debt.DebtModelPluginRepository; -import org.sonar.server.debt.DebtModelXMLExporter; -import org.sonar.server.debt.DebtRulesXMLImporter; -import org.sonar.server.duplication.ws.DuplicationsParser; -import org.sonar.server.duplication.ws.DuplicationsWs; -import org.sonar.server.duplication.ws.ShowResponseBuilder; -import org.sonar.server.email.ws.EmailsWsModule; -import org.sonar.server.es.IndexCreator; -import org.sonar.server.es.IndexDefinitions; -import org.sonar.server.es.ProjectIndexersImpl; -import org.sonar.server.es.RecoveryIndexer; -import org.sonar.server.es.metadata.EsDbCompatibilityImpl; -import org.sonar.server.es.metadata.MetadataIndexDefinition; -import org.sonar.server.es.metadata.MetadataIndexImpl; -import org.sonar.server.extension.CoreExtensionBootstraper; -import org.sonar.server.extension.CoreExtensionStopper; -import org.sonar.server.favorite.FavoriteModule; -import org.sonar.server.health.NodeHealthModule; -import org.sonar.server.issue.AddTagsAction; -import org.sonar.server.issue.AssignAction; -import org.sonar.server.issue.CommentAction; -import org.sonar.server.issue.IssueChangePostProcessorImpl; -import org.sonar.server.issue.RemoveTagsAction; -import org.sonar.server.issue.SetSeverityAction; -import org.sonar.server.issue.SetTypeAction; -import org.sonar.server.issue.TransitionAction; -import org.sonar.server.issue.index.IssueIndexDefinition; -import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.issue.index.IssueIteratorFactory; -import org.sonar.server.issue.notification.IssuesChangesNotificationModule; -import org.sonar.server.issue.notification.MyNewIssuesEmailTemplate; -import org.sonar.server.issue.notification.MyNewIssuesNotificationHandler; -import org.sonar.server.issue.notification.NewIssuesEmailTemplate; -import org.sonar.server.issue.notification.NewIssuesNotificationHandler; -import org.sonar.server.issue.ws.IssueWsModule; -import org.sonar.server.language.ws.LanguageWs; -import org.sonar.server.log.ServerLogging; -import org.sonar.server.measure.custom.ws.CustomMeasuresWsModule; -import org.sonar.server.measure.index.ProjectsEsModule; -import org.sonar.server.measure.live.LiveMeasureModule; -import org.sonar.server.measure.ws.MeasuresWsModule; -import org.sonar.server.measure.ws.TimeMachineWs; -import org.sonar.server.metric.CoreCustomMetrics; -import org.sonar.server.metric.DefaultMetricFinder; -import org.sonar.server.metric.ws.MetricsWsModule; -import org.sonar.server.notification.NotificationModule; -import org.sonar.server.notification.ws.NotificationWsModule; -import org.sonar.server.organization.BillingValidationsProxyImpl; -import org.sonar.server.organization.OrganizationUpdaterImpl; -import org.sonar.server.organization.OrganizationValidationImpl; -import org.sonar.server.organization.ws.OrganizationsWsModule; -import org.sonar.server.permission.GroupPermissionChanger; -import org.sonar.server.permission.PermissionTemplateService; -import org.sonar.server.permission.PermissionUpdater; -import org.sonar.server.permission.UserPermissionChanger; -import org.sonar.server.permission.index.PermissionIndexer; -import org.sonar.server.permission.ws.PermissionsWsModule; -import org.sonar.server.permission.ws.template.DefaultTemplatesResolverImpl; -import org.sonar.server.platform.BackendCleanup; -import org.sonar.server.platform.ClusterVerification; -import org.sonar.server.platform.PersistentSettings; -import org.sonar.server.platform.SettingsChangeNotifier; -import org.sonar.server.platform.WebCoreExtensionsInstaller; -import org.sonar.server.platform.monitoring.WebSystemInfoModule; -import org.sonar.server.platform.web.WebPagesFilter; -import org.sonar.server.platform.web.requestid.HttpRequestIdModule; -import org.sonar.server.platform.ws.ChangeLogLevelActionModule; -import org.sonar.server.platform.ws.DbMigrationStatusAction; -import org.sonar.server.platform.ws.HealthActionModule; -import org.sonar.server.platform.ws.L10nWs; -import org.sonar.server.platform.ws.LogsAction; -import org.sonar.server.platform.ws.MigrateDbAction; -import org.sonar.server.platform.ws.PingAction; -import org.sonar.server.platform.ws.RestartAction; -import org.sonar.server.platform.ws.ServerWs; -import org.sonar.server.platform.ws.StatusAction; -import org.sonar.server.platform.ws.SystemWs; -import org.sonar.server.platform.ws.UpgradesAction; -import org.sonar.server.plugins.PluginDownloader; -import org.sonar.server.plugins.PluginUninstaller; -import org.sonar.server.plugins.ServerExtensionInstaller; -import org.sonar.server.plugins.ws.AvailableAction; -import org.sonar.server.plugins.ws.CancelAllAction; -import org.sonar.server.plugins.ws.DownloadAction; -import org.sonar.server.plugins.ws.InstallAction; -import org.sonar.server.plugins.ws.InstalledAction; -import org.sonar.server.plugins.ws.PendingAction; -import org.sonar.server.plugins.ws.PluginUpdateAggregator; -import org.sonar.server.plugins.ws.PluginsWs; -import org.sonar.server.plugins.ws.UninstallAction; -import org.sonar.server.plugins.ws.UpdatesAction; -import org.sonar.server.project.ws.ProjectsWsModule; -import org.sonar.server.projectanalysis.ProjectAnalysisModule; -import org.sonar.server.projectlink.ws.ProjectLinksModule; -import org.sonar.server.projecttag.ws.ProjectTagsWsModule; -import org.sonar.server.property.InternalPropertiesImpl; -import org.sonar.server.property.ws.PropertiesWs; -import org.sonar.server.qualitygate.QualityGateModule; -import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler; -import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationHandler; -import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationTemplate; -import org.sonar.server.qualityprofile.BuiltInQProfileDefinitionsBridge; -import org.sonar.server.qualityprofile.BuiltInQProfileRepositoryImpl; -import org.sonar.server.qualityprofile.QProfileBackuperImpl; -import org.sonar.server.qualityprofile.QProfileComparison; -import org.sonar.server.qualityprofile.QProfileCopier; -import org.sonar.server.qualityprofile.QProfileExporters; -import org.sonar.server.qualityprofile.QProfileFactoryImpl; -import org.sonar.server.qualityprofile.QProfileResetImpl; -import org.sonar.server.qualityprofile.QProfileRulesImpl; -import org.sonar.server.qualityprofile.QProfileTreeImpl; -import org.sonar.server.qualityprofile.RuleActivator; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.qualityprofile.ws.QProfilesWsModule; -import org.sonar.server.root.ws.RootWsModule; -import org.sonar.server.rule.CommonRuleDefinitionsImpl; -import org.sonar.server.rule.DeprecatedRulesDefinitionLoader; -import org.sonar.server.rule.RuleCreator; -import org.sonar.server.rule.RuleDefinitionsLoader; -import org.sonar.server.rule.RuleUpdater; -import org.sonar.server.rule.WebServerRuleFinderImpl; -import org.sonar.server.rule.index.RuleIndexDefinition; -import org.sonar.server.rule.index.RuleIndexer; -import org.sonar.server.rule.ws.ActiveRuleCompleter; -import org.sonar.server.rule.ws.RepositoriesAction; -import org.sonar.server.rule.ws.RuleMapper; -import org.sonar.server.rule.ws.RuleQueryFactory; -import org.sonar.server.rule.ws.RuleWsSupport; -import org.sonar.server.rule.ws.RulesWs; -import org.sonar.server.rule.ws.TagsAction; -import org.sonar.server.setting.ws.SettingsWsModule; -import org.sonar.server.source.ws.SourceWsModule; -import org.sonar.server.startup.LogServerId; -import org.sonar.server.telemetry.TelemetryClient; -import org.sonar.server.telemetry.TelemetryDaemon; -import org.sonar.server.telemetry.TelemetryDataLoader; -import org.sonar.server.text.MacroInterpreter; -import org.sonar.server.ui.DeprecatedViews; -import org.sonar.server.ui.PageDecorations; -import org.sonar.server.ui.PageRepository; -import org.sonar.server.ui.WebAnalyticsLoaderImpl; -import org.sonar.server.ui.ws.NavigationWsModule; -import org.sonar.server.updatecenter.UpdateCenterModule; -import org.sonar.server.user.NewUserNotifier; -import org.sonar.server.user.SecurityRealmFactory; -import org.sonar.server.user.UserSessionFactoryImpl; -import org.sonar.server.user.UserUpdater; -import org.sonar.server.user.index.UserIndex; -import org.sonar.server.user.index.UserIndexDefinition; -import org.sonar.server.user.index.UserIndexer; -import org.sonar.server.user.ws.UsersWsModule; -import org.sonar.server.usergroups.DefaultGroupCreatorImpl; -import org.sonar.server.usergroups.DefaultGroupFinder; -import org.sonar.server.usergroups.ws.UserGroupsModule; -import org.sonar.server.usertoken.UserTokenModule; -import org.sonar.server.util.TypeValidationModule; -import org.sonar.server.view.index.ViewIndex; -import org.sonar.server.view.index.ViewIndexDefinition; -import org.sonar.server.view.index.ViewIndexer; -import org.sonar.server.webhook.WebhookModule; -import org.sonar.server.webhook.ws.WebhooksWsModule; -import org.sonar.server.ws.DeprecatedPropertiesWsFilter; -import org.sonar.server.ws.WebServiceEngine; -import org.sonar.server.ws.WebServiceFilter; -import org.sonar.server.ws.WebServiceReroutingFilter; -import org.sonar.server.ws.ws.WebServicesWsModule; - -import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; -import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel4OrNone; - -public class PlatformLevel4 extends PlatformLevel { - - private final List<Object> level4AddedComponents; - - public PlatformLevel4(PlatformLevel parent, List<Object> level4AddedComponents) { - super("level4", parent); - this.level4AddedComponents = level4AddedComponents; - } - - @Override - protected void configureLevel() { - addIfStartupLeader( - IndexCreator.class, - MetadataIndexDefinition.class, - MetadataIndexImpl.class, - EsDbCompatibilityImpl.class); - - addIfCluster(NodeHealthModule.class); - - add( - ClusterVerification.class, - LogServerId.class, - LogOAuthWarning.class, - PluginDownloader.class, - PluginUninstaller.class, - DeprecatedViews.class, - PageRepository.class, - ResourceTypes.class, - DefaultResourceTypes.get(), - SettingsChangeNotifier.class, - PageDecorations.class, - ServerWs.class, - BackendCleanup.class, - IndexDefinitions.class, - WebPagesFilter.class, - WebAnalyticsLoaderImpl.class, - - // batch - BatchWsModule.class, - - // update center - UpdateCenterModule.class, - - // organizations - OrganizationValidationImpl.class, - OrganizationUpdaterImpl.class, - OrganizationsWsModule.class, - BillingValidationsProxyImpl.class, - - // quality profile - BuiltInQProfileDefinitionsBridge.class, - BuiltInQProfileRepositoryImpl.class, - ActiveRuleIndexer.class, - XMLProfileParser.class, - XMLProfileSerializer.class, - AnnotationProfileParser.class, - QProfileComparison.class, - QProfileTreeImpl.class, - QProfileRulesImpl.class, - RuleActivator.class, - QProfileExporters.class, - QProfileFactoryImpl.class, - QProfileCopier.class, - QProfileBackuperImpl.class, - QProfileResetImpl.class, - QProfilesWsModule.class, - - // rule - RuleIndexDefinition.class, - RuleIndexer.class, - AnnotationRuleParser.class, - XMLRuleParser.class, - WebServerRuleFinderImpl.class, - DeprecatedRulesDefinitionLoader.class, - RuleDefinitionsLoader.class, - CommonRuleDefinitionsImpl.class, - RulesDefinitionXmlLoader.class, - RuleUpdater.class, - RuleCreator.class, - org.sonar.server.rule.ws.UpdateAction.class, - RulesWs.class, - RuleWsSupport.class, - org.sonar.server.rule.ws.SearchAction.class, - org.sonar.server.rule.ws.ShowAction.class, - org.sonar.server.rule.ws.CreateAction.class, - org.sonar.server.rule.ws.DeleteAction.class, - org.sonar.server.rule.ws.ListAction.class, - TagsAction.class, - RuleMapper.class, - ActiveRuleCompleter.class, - RepositoriesAction.class, - RuleQueryFactory.class, - org.sonar.server.rule.ws.AppAction.class, - - // languages - Languages.class, - LanguageWs.class, - org.sonar.server.language.ws.ListAction.class, - - // measure - MetricsWsModule.class, - MeasuresWsModule.class, - CustomMeasuresWsModule.class, - CoreCustomMetrics.class, - DefaultMetricFinder.class, - TimeMachineWs.class, - - QualityGateModule.class, - - // web services - WebServiceEngine.class, - WebServicesWsModule.class, - WebServiceFilter.class, - DeprecatedPropertiesWsFilter.class, - WebServiceReroutingFilter.class, - - // localization - L10nWs.class, - org.sonar.server.platform.ws.IndexAction.class, - - // authentication - AuthenticationModule.class, - - // users - UserSessionFactoryImpl.class, - SecurityRealmFactory.class, - NewUserNotifier.class, - UserIndexDefinition.class, - UserIndexer.class, - UserIndex.class, - UserUpdater.class, - UsersWsModule.class, - UserTokenModule.class, - - // groups - UserGroupsModule.class, - DefaultGroupCreatorImpl.class, - DefaultGroupFinder.class, - - // permissions - DefaultTemplatesResolverImpl.class, - PermissionsWsModule.class, - PermissionTemplateService.class, - PermissionUpdater.class, - UserPermissionChanger.class, - GroupPermissionChanger.class, - - // components - BranchWsModule.class, - PullRequestWsModule.class, - ProjectsWsModule.class, - ProjectsEsModule.class, - ProjectTagsWsModule.class, - ComponentsWsModule.class, - ComponentService.class, - ComponentUpdater.class, - ComponentFinder.class, - QGChangeNotificationHandler.class, - QGChangeNotificationHandler.newMetadata(), - ComponentCleanerService.class, - ComponentIndexDefinition.class, - ComponentIndex.class, - ComponentIndexer.class, - LiveMeasureModule.class, - ComponentViewerJsonWriter.class, - - FavoriteModule.class, - - // views - ViewIndexDefinition.class, - ViewIndexer.class, - ViewIndex.class, - - // issues - IssueIndexDefinition.class, - IssueIndexer.class, - IssueIteratorFactory.class, - PermissionIndexer.class, - IssueWsModule.class, - NewIssuesEmailTemplate.class, - MyNewIssuesEmailTemplate.class, - IssuesChangesNotificationModule.class, - NewIssuesNotificationHandler.class, - NewIssuesNotificationHandler.newMetadata(), - MyNewIssuesNotificationHandler.class, - MyNewIssuesNotificationHandler.newMetadata(), - - // issues actions - AssignAction.class, - SetTypeAction.class, - SetSeverityAction.class, - CommentAction.class, - TransitionAction.class, - AddTagsAction.class, - RemoveTagsAction.class, - IssueChangePostProcessorImpl.class, - - // technical debt - DebtModelPluginRepository.class, - DebtModelXMLExporter.class, - DebtRulesXMLImporter.class, - - // source - SourceWsModule.class, - - // Duplications - DuplicationsParser.class, - DuplicationsWs.class, - ShowResponseBuilder.class, - org.sonar.server.duplication.ws.ShowAction.class, - - // text - MacroInterpreter.class, - - // Notifications - // Those class are required in order to be able to send emails during startup - // Without having two NotificationModule (one in StartupLevel and one in Level4) - BuiltInQPChangeNotificationTemplate.class, - BuiltInQPChangeNotificationHandler.class, - - NotificationModule.class, - NotificationWsModule.class, - EmailsWsModule.class, - - // Settings - PersistentSettings.class, - PropertiesWs.class, - org.sonar.server.property.ws.IndexAction.class, - SettingsWsModule.class, - - TypeValidationModule.class, - - // Project Links - ProjectLinksModule.class, - - // Project Analyses - ProjectAnalysisModule.class, - - // System - ServerLogging.class, - RestartAction.class, - PingAction.class, - UpgradesAction.class, - StatusAction.class, - MigrateDbAction.class, - LogsAction.class, - ChangeLogLevelActionModule.class, - DbMigrationStatusAction.class, - HealthActionModule.class, - SystemWs.class, - - // Plugins WS - PluginUpdateAggregator.class, - InstalledAction.class, - AvailableAction.class, - DownloadAction.class, - UpdatesAction.class, - PendingAction.class, - InstallAction.class, - org.sonar.server.plugins.ws.UpdateAction.class, - UninstallAction.class, - CancelAllAction.class, - PluginsWs.class, - - // Branch - BranchFeatureProxyImpl.class, - - // Project badges - ProjectBadgesWsModule.class, - - // Core Extensions - CoreExtensionBootstraper.class, - CoreExtensionStopper.class, - - // Compute engine (must be after Views and Developer Cockpit) - ReportAnalysisFailureNotificationModule.class, - CeModule.class, - CeWsModule.class, - - // SonarSource editions - PlatformEditionProvider.class, - - InternalPropertiesImpl.class, - - // UI - NavigationWsModule.class, - - // root - RootWsModule.class, - - // webhooks - WebhookModule.class, - WebhooksWsModule.class, - - // Http Request ID - HttpRequestIdModule.class, - - RecoveryIndexer.class, - ProjectIndexersImpl.class, - - // telemetry - TelemetryDataLoader.class, - TelemetryDaemon.class, - TelemetryClient.class - - ); - - // system info - add(WebSystemInfoModule.class); - - addAll(level4AddedComponents); - } - - @Override - public PlatformLevel start() { - ComponentContainer container = getContainer(); - CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); - coreExtensionsInstaller.install(container, hasPlatformLevel4OrNone(), noAdditionalSideFilter()); - ServerExtensionInstaller extensionInstaller = get(ServerExtensionInstaller.class); - extensionInstaller.installExtensions(container); - - super.start(); - - return this; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java deleted file mode 100644 index eea1137d7b4..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import org.sonar.server.platform.ws.SafeModeHealthActionModule; -import org.sonar.server.authentication.SafeModeUserSession; -import org.sonar.server.organization.NoopDefaultOrganizationCache; -import org.sonar.server.platform.ServerImpl; -import org.sonar.server.platform.db.migration.AutoDbMigration; -import org.sonar.server.platform.db.migration.DatabaseMigrationImpl; -import org.sonar.server.platform.db.migration.MigrationEngineModule; -import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl; -import org.sonar.server.platform.web.WebPagesFilter; -import org.sonar.server.platform.ws.DbMigrationStatusAction; -import org.sonar.server.platform.ws.IndexAction; -import org.sonar.server.platform.ws.L10nWs; -import org.sonar.server.platform.ws.MigrateDbAction; -import org.sonar.server.platform.ws.StatusAction; -import org.sonar.server.platform.ws.SystemWs; -import org.sonar.server.ws.WebServiceEngine; -import org.sonar.server.ws.WebServiceFilter; -import org.sonar.server.ws.ws.WebServicesWsModule; - -public class PlatformLevelSafeMode extends PlatformLevel { - public PlatformLevelSafeMode(PlatformLevel parent) { - super("Safemode", parent); - } - - @Override - protected void configureLevel() { - add( - ServerImpl.class, - WebPagesFilter.class, - - // l10n WS - L10nWs.class, - IndexAction.class, - - // Server WS - StatusAction.class, - MigrateDbAction.class, - DbMigrationStatusAction.class, - SafeModeHealthActionModule.class, - SystemWs.class, - - // Listing WS - WebServicesWsModule.class, - - // WS engine - SafeModeUserSession.class, - WebServiceEngine.class, - WebServiceFilter.class, - - NoopDefaultOrganizationCache.class); - addIfStartupLeader( - DatabaseMigrationImpl.class, - MigrationEngineModule.class, - AutoDbMigration.class) - .otherwiseAdd(NoopDatabaseMigrationImpl.class); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java deleted file mode 100644 index 1fb52415beb..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.platform.EditionProvider; -import org.sonar.core.platform.PlatformEditionProvider; -import org.sonar.server.app.ProcessCommandWrapper; -import org.sonar.server.ce.queue.CeQueueCleaner; -import org.sonar.server.es.IndexerStartupTask; -import org.sonar.server.organization.DefaultOrganizationEnforcer; -import org.sonar.server.platform.ServerLifecycleNotifier; -import org.sonar.server.platform.web.RegisterServletFilters; -import org.sonar.server.qualitygate.ProjectsInWarningDaemon; -import org.sonar.server.qualitygate.RegisterQualityGates; -import org.sonar.server.qualityprofile.BuiltInQProfileInsertImpl; -import org.sonar.server.qualityprofile.BuiltInQProfileLoader; -import org.sonar.server.qualityprofile.BuiltInQProfileUpdateImpl; -import org.sonar.server.qualityprofile.BuiltInQualityProfilesUpdateListener; -import org.sonar.server.qualityprofile.RegisterQualityProfiles; -import org.sonar.server.rule.RegisterRules; -import org.sonar.server.rule.WebServerRuleFinder; -import org.sonar.server.startup.GeneratePluginIndex; -import org.sonar.server.startup.RegisterMetrics; -import org.sonar.server.startup.RegisterPermissionTemplates; -import org.sonar.server.startup.RegisterPlugins; -import org.sonar.server.startup.RenameDeprecatedPropertyKeys; -import org.sonar.server.user.DoPrivileged; -import org.sonar.server.user.ThreadLocalUserSession; - -public class PlatformLevelStartup extends PlatformLevel { - public PlatformLevelStartup(PlatformLevel parent) { - super("startup tasks", parent); - } - - @Override - protected void configureLevel() { - add(GeneratePluginIndex.class, - RegisterPlugins.class, - ServerLifecycleNotifier.class, - DefaultOrganizationEnforcer.class); - - addIfStartupLeader( - IndexerStartupTask.class, - RegisterMetrics.class, - RegisterQualityGates.class, - RegisterRules.class); - add(BuiltInQProfileLoader.class); - addIfStartupLeader( - BuiltInQualityProfilesUpdateListener.class, - BuiltInQProfileInsertImpl.class, - BuiltInQProfileUpdateImpl.class, - RegisterQualityProfiles.class, - RegisterPermissionTemplates.class, - RenameDeprecatedPropertyKeys.class, - CeQueueCleaner.class); - - // RegisterServletFilters makes the WebService engine of Level4 served by the MasterServletFilter, therefor it - // must be started after all the other startup tasks - add(RegisterServletFilters.class); - } - - @Override - public PlatformLevel start() { - DoPrivileged.execute(new DoPrivileged.Task(get(ThreadLocalUserSession.class)) { - @Override - protected void doPrivileged() { - PlatformLevelStartup.super.start(); - getOptional(IndexerStartupTask.class).ifPresent(IndexerStartupTask::execute); - // Need to be executed after indexing as it executes an ES query - get(ProjectsInWarningDaemon.class).notifyStart(); - get(ServerLifecycleNotifier.class).notifyStart(); - get(ProcessCommandWrapper.class).notifyOperational(); - get(WebServerRuleFinder.class).stopCaching(); - Loggers.get(PlatformLevelStartup.class) - .info("Running {} Edition", get(PlatformEditionProvider.class).get().map(EditionProvider.Edition::getLabel).orElse("")); - } - }); - - return this; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/package-info.java deleted file mode 100644 index a147f3acf02..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/CacheControlFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/CacheControlFilter.java deleted file mode 100644 index 1b257aa9ded..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/CacheControlFilter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.collect.ImmutableMap; -import java.io.IOException; -import java.util.Map; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import static java.lang.String.format; - -/** - * This servlet filter sets response headers that enable cache control on some static resources - */ -public class CacheControlFilter implements Filter { - - private static final String CACHE_CONTROL_HEADER = "Cache-Control"; - - /** - * Recommended max value for max-age is 1 year - * @see <a href="https://stackoverflow.com/questions/7071763/max-value-for-cache-control-header-in-http">stackoverflow thread</a> - */ - private static final int ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60; - - private static final int FIVE_MINUTES_IN_SECONDS = 5 * 60; - - private static final String MAX_AGE_TEMPLATE = "max-age=%d"; - - private static final Map<String, Integer> MAX_AGE_BY_PATH = ImmutableMap.of( - // These folders contains files that are suffixed with their content hash : the cache should never be invalidated - "/js/", ONE_YEAR_IN_SECONDS, - "/css/", ONE_YEAR_IN_SECONDS, - // This folder contains static resources from plugins : the cache should be set to a small value - "/static/", FIVE_MINUTES_IN_SECONDS, - "/images/", FIVE_MINUTES_IN_SECONDS); - - @Override - public void init(FilterConfig filterConfig) { - // nothing - } - - @Override - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { - String path = ((HttpServletRequest) req).getRequestURI().replaceFirst(((HttpServletRequest) req).getContextPath(), ""); - - MAX_AGE_BY_PATH.entrySet().stream() - .filter(m -> path.startsWith(m.getKey())) - .map(Map.Entry::getValue) - .findFirst() - .ifPresent(maxAge -> ((HttpServletResponse) resp).addHeader(CACHE_CONTROL_HEADER, format(MAX_AGE_TEMPLATE, maxAge))); - - chain.doFilter(req, resp); - } - - @Override - public void destroy() { - // nothing - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/MasterServletFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/MasterServletFilter.java deleted file mode 100644 index a2de9a5e0b6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/MasterServletFilter.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.web.ServletFilter; -import org.sonar.server.platform.Platform; - -/** - * Inspired by http://stackoverflow.com/a/7592883/229031 - */ -public class MasterServletFilter implements Filter { - - public static volatile MasterServletFilter INSTANCE; - private ServletFilter[] filters; - private FilterConfig config; - - public MasterServletFilter() { - if (INSTANCE != null) { - throw new IllegalStateException("Servlet filter " + getClass().getName() + " is already instantiated"); - } - INSTANCE = this; - } - - @Override - public void init(FilterConfig config) { - // Filters are already available in picocontainer unless a database migration is required. See - // org.sonar.server.startup.RegisterServletFilters. - init(config, Platform.getInstance().getContainer().getComponentsByType(ServletFilter.class)); - } - - void init(FilterConfig config, List<ServletFilter> filters) { - this.config = config; - initFilters(filters); - } - - public void initFilters(List<ServletFilter> filterExtensions) { - List<ServletFilter> filterList = Lists.newArrayList(); - for (ServletFilter extension : filterExtensions) { - try { - Loggers.get(MasterServletFilter.class).info(String.format("Initializing servlet filter %s [pattern=%s]", extension, extension.doGetPattern().label())); - extension.init(config); - filterList.add(extension); - } catch (Exception e) { - throw new IllegalStateException("Fail to initialize servlet filter: " + extension + ". Message: " + e.getMessage(), e); - } - } - filters = filterList.toArray(new ServletFilter[filterList.size()]); - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { - HttpServletRequest hsr = (HttpServletRequest) request; - if (filters.length == 0) { - chain.doFilter(hsr, response); - } else { - String path = hsr.getRequestURI().replaceFirst(hsr.getContextPath(), ""); - GodFilterChain godChain = new GodFilterChain(chain); - - for (ServletFilter filter : filters) { - if (filter.doGetPattern().matches(path)) { - godChain.addFilter(filter); - } - } - godChain.doFilter(hsr, response); - } - } - - @Override - public void destroy() { - for (ServletFilter filter : filters) { - filter.destroy(); - } - } - - @VisibleForTesting - ServletFilter[] getFilters() { - return filters; - } - - private static final class GodFilterChain implements FilterChain { - private FilterChain chain; - private List<Filter> filters = Lists.newLinkedList(); - private Iterator<Filter> iterator; - - public GodFilterChain(FilterChain chain) { - this.chain = chain; - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { - if (iterator == null) { - iterator = filters.iterator(); - } - if (iterator.hasNext()) { - iterator.next().doFilter(request, response, this); - } else { - chain.doFilter(request, response); - } - } - - public void addFilter(Filter filter) { - Preconditions.checkState(iterator == null); - filters.add(filter); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/PlatformServletContextListener.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/PlatformServletContextListener.java deleted file mode 100644 index cfc68edd915..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/PlatformServletContextListener.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.util.Enumeration; -import java.util.Properties; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import org.sonar.api.utils.log.Loggers; -import org.sonar.server.platform.Platform; - -public final class PlatformServletContextListener implements ServletContextListener { - static final String STARTED_ATTRIBUTE = "sonarqube.started"; - - @Override - public void contextInitialized(ServletContextEvent event) { - try { - Properties props = new Properties(); - ServletContext servletContext = event.getServletContext(); - Enumeration<String> paramKeys = servletContext.getInitParameterNames(); - while (paramKeys.hasMoreElements()) { - String key = paramKeys.nextElement(); - props.put(key, servletContext.getInitParameter(key)); - } - Platform.getInstance().init(props, servletContext); - Platform.getInstance().doStart(); - event.getServletContext().setAttribute(STARTED_ATTRIBUTE, Boolean.TRUE); - } catch (org.sonar.api.utils.MessageException | org.sonar.process.MessageException e) { - Loggers.get(Platform.class).error("Web server startup failed: " + e.getMessage()); - stopQuietly(); - } catch (Throwable t) { - Loggers.get(Platform.class).error("Web server startup failed", t); - stopQuietly(); - throw new AbortTomcatStartException(); - } - } - - private void stopQuietly() { - try { - Platform.getInstance().doStop(); - } catch (Exception e) { - // ignored, but an error during startup generally prevents pico to be correctly stopped - } - } - - @Override - public void contextDestroyed(ServletContextEvent event) { - Platform.getInstance().doStop(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/RedirectFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/RedirectFilter.java deleted file mode 100644 index 64a17466641..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/RedirectFilter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.collect.ImmutableList; -import java.io.IOException; -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.sonar.core.util.stream.MoreCollectors; - -import static java.lang.String.format; - -public class RedirectFilter implements Filter { - - private static final String EMPTY = ""; - - private static final List<Redirect> REDIRECTS = ImmutableList.of( - newSimpleRedirect("/api", "/api/webservices/list")); - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - String path = extractPath(request); - Predicate<Redirect> match = redirect -> redirect.test(path); - List<Redirect> redirects = REDIRECTS.stream() - .filter(match) - .collect(MoreCollectors.toList()); - - switch (redirects.size()) { - case 0: - chain.doFilter(request, response); - break; - case 1: - response.sendRedirect(redirects.get(0).apply(request)); - break; - default: - throw new IllegalStateException(format("Multiple redirects have been found for '%s'", path)); - } - } - - public static Redirect newSimpleRedirect(String from, String to) { - return new Redirect() { - @Override - public boolean test(String path) { - return from.equals(path); - } - - @Override - public String apply(HttpServletRequest request) { - return format("%s%s", request.getContextPath(), to); - } - }; - } - - @Override - public void init(FilterConfig filterConfig) { - // Nothing - } - - @Override - public void destroy() { - // Nothing - } - - private interface Redirect extends Predicate<String>, Function<HttpServletRequest, String> { - @Override - boolean test(String path); - - @Override - String apply(HttpServletRequest request); - } - - private static String extractPath(HttpServletRequest request) { - return sanitizePath(request.getRequestURI().replaceFirst(request.getContextPath(), EMPTY)); - } - - private static String sanitizePath(String path) { - if (path.length() > 1 && path.endsWith("/")) { - return path.substring(0, path.length() - 1); - } - return path; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/RegisterServletFilters.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/RegisterServletFilters.java deleted file mode 100644 index 88b1692362e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/RegisterServletFilters.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.util.Arrays; -import org.picocontainer.Startable; -import org.sonar.api.web.ServletFilter; - -/** - * @since 3.5 - */ -public class RegisterServletFilters implements Startable { - private final ServletFilter[] filters; - - public RegisterServletFilters(ServletFilter[] filters) { - this.filters = filters; - } - - public RegisterServletFilters() { - this(new ServletFilter[0]); - } - - @Override - public void start() { - if (MasterServletFilter.INSTANCE != null) { - // Probably a database upgrade. MasterSlaveFilter was instantiated by the servlet container - // while picocontainer was not completely up. - // See https://jira.sonarsource.com/browse/SONAR-3612 - MasterServletFilter.INSTANCE.initFilters(Arrays.asList(filters)); - } - } - - @Override - public void stop() { - // nothing to do - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/SecurityServletFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/SecurityServletFilter.java deleted file mode 100644 index a8d1dd55cae..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/SecurityServletFilter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.collect.ImmutableSet; -import java.io.IOException; -import java.util.Set; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * This servlet filter sets response headers that enable browser protection against several classes if Web attacks. - */ -public class SecurityServletFilter implements Filter { - - private static final Set<String> ALLOWED_HTTP_METHODS = ImmutableSet.of("DELETE", "GET", "HEAD", "POST", "PUT"); - - @Override - public void init(FilterConfig filterConfig) { - // nothing - } - - @Override - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { - doHttpFilter((HttpServletRequest) req, (HttpServletResponse) resp, chain); - } - - private static void doHttpFilter(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain) throws IOException, ServletException { - // SONAR-6881 Disable OPTIONS and TRACE methods - if (!ALLOWED_HTTP_METHODS.contains(httpRequest.getMethod())) { - httpResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - return; - } - - // WARNING, headers must be added before the doFilter, otherwise they won't be added when response is already committed (for instance when a WS is called) - - // Clickjacking protection - // See https://www.owasp.org/index.php/Clickjacking_Protection_for_Java_EE - // The protection is disabled on purpose for integration in external systems like VSTS (/integration/vsts/index.html). - String path = httpRequest.getRequestURI().replaceFirst(httpRequest.getContextPath(), ""); - if (!path.startsWith("/integration/")) { - httpResponse.addHeader("X-Frame-Options", "SAMEORIGIN"); - } - - // Cross-site scripting - // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers - httpResponse.addHeader("X-XSS-Protection", "1; mode=block"); - - // MIME-sniffing - // See https://www.owasp.org/index.php/List_of_useful_HTTP_headers - httpResponse.addHeader("X-Content-Type-Options", "nosniff"); - - chain.doFilter(httpRequest, httpResponse); - } - - @Override - public void destroy() { - // nothing - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesCache.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesCache.java deleted file mode 100644 index ba4eedbc85d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesCache.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.collect.ImmutableSet; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import javax.servlet.ServletContext; -import org.apache.commons.io.IOUtils; -import org.sonar.api.config.Configuration; -import org.sonar.server.platform.OfficialDistribution; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.Platform.Status; - -import static com.google.common.base.Preconditions.checkState; -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Objects.requireNonNull; -import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED; -import static org.sonar.server.platform.Platform.Status.UP; - -public class WebPagesCache { - - private static final String WEB_CONTEXT_PLACEHOLDER = "%WEB_CONTEXT%"; - private static final String SERVER_STATUS_PLACEHOLDER = "%SERVER_STATUS%"; - private static final String INSTANCE_PLACEHOLDER = "%INSTANCE%"; - private static final String OFFICIAL_PLACEHOLDER = "%OFFICIAL%"; - - private static final String SONARCLOUD_INSTANCE_VALUE = "SonarCloud"; - private static final String SONARQUBE_INSTANCE_VALUE = "SonarQube"; - - private static final String INDEX_HTML_PATH = "/index.html"; - - private static final Set<String> HTML_PATHS = ImmutableSet.of(INDEX_HTML_PATH, "/integration/vsts/index.html"); - - private final Platform platform; - private final Configuration configuration; - private final OfficialDistribution officialDistribution; - - private ServletContext servletContext; - private Map<String, String> indexHtmlByPath; - private Status status; - - public WebPagesCache(Platform platform, Configuration configuration, OfficialDistribution officialDistribution) { - this.platform = platform; - this.configuration = configuration; - this.indexHtmlByPath = new HashMap<>(); - this.officialDistribution = officialDistribution; - } - - public void init(ServletContext servletContext) { - this.servletContext = servletContext; - generate(platform.status()); - } - - public String getContent(String path) { - String htmlPath = HTML_PATHS.contains(path) ? path : INDEX_HTML_PATH; - checkState(servletContext != null, "init has not been called"); - // Optimization to not have to call platform.currentStatus on each call - if (Objects.equals(status, UP)) { - return indexHtmlByPath.get(htmlPath); - } - Status currentStatus = platform.status(); - if (!Objects.equals(status, currentStatus)) { - generate(currentStatus); - } - return indexHtmlByPath.get(htmlPath); - } - - private void generate(Status status) { - this.status = status; - HTML_PATHS.forEach(path -> indexHtmlByPath.put(path, provide(path))); - } - - private String provide(String path) { - getClass().getResourceAsStream(INDEX_HTML_PATH); - boolean isSonarCloud = configuration.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false); - String instance = isSonarCloud ? SONARCLOUD_INSTANCE_VALUE : SONARQUBE_INSTANCE_VALUE; - return loadHtmlFile(path, status.name(), instance); - } - - private String loadHtmlFile(String path, String serverStatus, String instance) { - try (InputStream input = servletContext.getResourceAsStream(path)) { - String template = IOUtils.toString(requireNonNull(input), UTF_8); - return template - .replaceAll(WEB_CONTEXT_PLACEHOLDER, servletContext.getContextPath()) - .replaceAll(SERVER_STATUS_PLACEHOLDER, serverStatus) - .replaceAll(INSTANCE_PLACEHOLDER, instance) - .replaceAll(OFFICIAL_PLACEHOLDER, String.valueOf(officialDistribution.check())); - } catch (Exception e) { - throw new IllegalStateException("Fail to load file " + path, e); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesFilter.java deleted file mode 100644 index d464f62f603..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/WebPagesFilter.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import com.google.common.annotations.VisibleForTesting; -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.sonar.api.web.ServletFilter; -import org.sonar.server.platform.Platform; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Locale.ENGLISH; -import static java.util.Objects.requireNonNull; -import static org.apache.commons.io.IOUtils.write; -import static org.sonar.api.web.ServletFilter.UrlPattern.Builder.staticResourcePatterns; -import static org.sonarqube.ws.MediaTypes.HTML; - -/** - * This filter provide the HTML file that will be used to display every web pages. - * The same file should be provided for any URLs except WS and static resources. - */ -public class WebPagesFilter implements Filter { - - private static final String CACHE_CONTROL_HEADER = "Cache-Control"; - private static final String CACHE_CONTROL_VALUE = "no-cache, no-store, must-revalidate"; - - private static final ServletFilter.UrlPattern URL_PATTERN = ServletFilter.UrlPattern - .builder() - .excludes(staticResourcePatterns()) - .build(); - - private WebPagesCache webPagesCache; - - public WebPagesFilter() { - this(Platform.getInstance().getContainer().getComponentByType(WebPagesCache.class)); - } - - @VisibleForTesting - WebPagesFilter(WebPagesCache webPagesCache) { - this.webPagesCache = webPagesCache; - } - - @Override - public void init(FilterConfig filterConfig) { - webPagesCache.init(filterConfig.getServletContext()); - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - String path = httpServletRequest.getRequestURI().replaceFirst(httpServletRequest.getContextPath(), ""); - if (!URL_PATTERN.matches(path)) { - chain.doFilter(request, response); - return; - } - httpServletResponse.setContentType(HTML); - httpServletResponse.setCharacterEncoding(UTF_8.name().toLowerCase(ENGLISH)); - httpServletResponse.setHeader(CACHE_CONTROL_HEADER, CACHE_CONTROL_VALUE); - - String htmlContent = requireNonNull(webPagesCache.getContent(path)); - write(htmlContent, httpServletResponse.getOutputStream(), UTF_8); - } - - @Override - public void destroy() { - // Nothing to do - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdFilter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdFilter.java deleted file mode 100644 index ea9e5d5acf5..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web.requestid; - -import com.google.common.annotations.VisibleForTesting; -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import org.sonar.server.platform.Platform; - -/** - * A {@link Filter} that puts and removes the HTTP request ID from the {@link org.slf4j.MDC}. - */ -public class RequestIdFilter implements Filter { - - private final Platform platform; - - public RequestIdFilter() { - this(Platform.getInstance()); - } - - @VisibleForTesting - RequestIdFilter(Platform platform) { - this.platform = platform; - } - - @Override - public void init(FilterConfig filterConfig) { - // nothing to do - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - RequestIdGenerator requestIdGenerator = platform.getContainer().getComponentByType(RequestIdGenerator.class); - - if (requestIdGenerator == null) { - chain.doFilter(request, response); - } else { - String requestId = requestIdGenerator.generate(); - try (RequestIdMDCStorage mdcStorage = new RequestIdMDCStorage(requestId)) { - request.setAttribute("ID", requestId); - chain.doFilter(request, response); - } - } - } - - @Override - public void destroy() { - // nothing to do - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdMDCStorage.java b/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdMDCStorage.java index 7e23a7627a7..53b4bf49e33 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdMDCStorage.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/web/requestid/RequestIdMDCStorage.java @@ -29,7 +29,7 @@ import static java.util.Objects.requireNonNull; public class RequestIdMDCStorage implements AutoCloseable { public static final String HTTP_REQUEST_ID_MDC_KEY = "HTTP_REQUEST_ID"; - RequestIdMDCStorage(String requestId) { + public RequestIdMDCStorage(String requestId) { MDC.put(HTTP_REQUEST_ID_MDC_KEY, requireNonNull(requestId, "Request ID can't be null")); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java deleted file mode 100644 index d32cc9e64f9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.plugins; - -import com.google.common.annotations.VisibleForTesting; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import javax.annotation.CheckForNull; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.connector.ClientAbortException; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.core.platform.PluginRepository; -import org.sonar.core.extension.CoreExtensionRepository; -import org.sonar.server.platform.Platform; -import org.sonarqube.ws.MediaTypes; - -import static java.lang.String.format; -import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; -import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; - -public class StaticResourcesServlet extends HttpServlet { - - private static final Logger LOG = Loggers.get(StaticResourcesServlet.class); - private static final long serialVersionUID = -2577454614650178426L; - - private final System system; - - @VisibleForTesting - StaticResourcesServlet(System system) { - this.system = system; - } - - public StaticResourcesServlet() { - this.system = new System(); - } - - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) { - String pluginKey = getPluginKey(request); - String resource = getResourcePath(request); - InputStream in = null; - OutputStream out = null; - try { - CoreExtensionRepository coreExtensionRepository = system.getCoreExtensionRepository(); - PluginRepository pluginRepository = system.getPluginRepository(); - - boolean coreExtension = coreExtensionRepository.isInstalled(pluginKey); - if (!coreExtension && !pluginRepository.hasPlugin(pluginKey)) { - silentlySendError(response, SC_NOT_FOUND); - return; - } - - in = coreExtension ? system.openCoreExtensionResourceStream(resource) : system.openPluginResourceStream(pluginKey, resource, pluginRepository); - if (in == null) { - silentlySendError(response, SC_NOT_FOUND); - return; - } - - // mime type must be set before writing response body - completeContentType(response, resource); - out = response.getOutputStream(); - IOUtils.copy(in, out); - } catch (ClientAbortException e) { - LOG.trace("Client canceled loading resource [{}] from plugin [{}]: {}", resource, pluginKey, e); - } catch (Exception e) { - LOG.error(format("Unable to load resource [%s] from plugin [%s]", resource, pluginKey), e); - silentlySendError(response, SC_INTERNAL_SERVER_ERROR); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - } - } - - private void silentlySendError(HttpServletResponse response, int error) { - if (system.isCommitted(response)) { - LOG.trace("Response is committed. Cannot send error response code {}", error); - return; - } - try { - system.sendError(response, error); - } catch (IOException e) { - LOG.trace("Failed to send error code {}: {}", error, e); - } - } - - /** - * @return part of request URL after servlet path - */ - private static String getPluginKeyAndResourcePath(HttpServletRequest request) { - return StringUtils.substringAfter(request.getRequestURI(), request.getContextPath() + request.getServletPath() + "/"); - } - - private static String getPluginKey(HttpServletRequest request) { - return StringUtils.substringBefore(getPluginKeyAndResourcePath(request), "/"); - } - - /** - * Note that returned value should not have a leading "/" - see {@link Class#resolveName(String)}. - */ - private static String getResourcePath(HttpServletRequest request) { - return "static/" + StringUtils.substringAfter(getPluginKeyAndResourcePath(request), "/"); - } - - private static void completeContentType(HttpServletResponse response, String filename) { - response.setContentType(MediaTypes.getByFilename(filename)); - } - - static class System { - PluginRepository getPluginRepository() { - return Platform.getInstance().getContainer().getComponentByType(PluginRepository.class); - } - - CoreExtensionRepository getCoreExtensionRepository() { - return Platform.getInstance().getContainer().getComponentByType(CoreExtensionRepository.class); - } - - @CheckForNull - InputStream openPluginResourceStream(String pluginKey, String resource, PluginRepository pluginRepository) throws Exception { - ClassLoader pluginClassLoader = pluginRepository.getPluginInstance(pluginKey).getClass().getClassLoader(); - return pluginClassLoader.getResourceAsStream(resource); - } - - @CheckForNull - InputStream openCoreExtensionResourceStream(String resource) throws Exception { - return getClass().getClassLoader().getResourceAsStream(resource); - } - - boolean isCommitted(HttpServletResponse response) { - return response.isCommitted(); - } - - void sendError(HttpServletResponse response, int error) throws IOException { - response.sendError(error); - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java deleted file mode 100644 index bac3d96138d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/user/UserSessionFilter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.user; - -import com.google.common.annotations.VisibleForTesting; -import java.io.IOException; -import javax.annotation.Nullable; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.sonar.db.DBSessions; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.server.authentication.UserSessionInitializer; -import org.sonar.server.organization.DefaultOrganizationCache; -import org.sonar.server.platform.Platform; -import org.sonar.server.setting.ThreadLocalSettings; - -public class UserSessionFilter implements Filter { - private static final Logger LOG = Loggers.get(UserSessionFilter.class); - private final Platform platform; - - public UserSessionFilter() { - this.platform = Platform.getInstance(); - } - - @VisibleForTesting - UserSessionFilter(Platform platform) { - this.platform = platform; - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - - DBSessions dbSessions = platform.getContainer().getComponentByType(DBSessions.class); - ThreadLocalSettings settings = platform.getContainer().getComponentByType(ThreadLocalSettings.class); - DefaultOrganizationCache defaultOrganizationCache = platform.getContainer().getComponentByType(DefaultOrganizationCache.class); - UserSessionInitializer userSessionInitializer = platform.getContainer().getComponentByType(UserSessionInitializer.class); - - LOG.trace("{} serves {}", Thread.currentThread(), request.getRequestURI()); - dbSessions.enableCaching(); - try { - defaultOrganizationCache.load(); - try { - settings.load(); - try { - doFilter(request, response, chain, userSessionInitializer); - } finally { - settings.unload(); - } - } finally { - defaultOrganizationCache.unload(); - } - } finally { - dbSessions.disableCaching(); - } - } - - private static void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain, - @Nullable UserSessionInitializer userSessionInitializer) throws IOException, ServletException { - try { - if (userSessionInitializer == null || userSessionInitializer.initUserSession(request, response)) { - chain.doFilter(request, response); - } - } finally { - if (userSessionInitializer != null) { - userSessionInitializer.removeUserSession(); - } - } - } - - @Override - public void init(FilterConfig filterConfig) { - // nothing to do - } - - @Override - public void destroy() { - // nothing to do - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/EmbeddedTomcatTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/EmbeddedTomcatTest.java deleted file mode 100644 index 26c2d23a37e..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/EmbeddedTomcatTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import java.io.File; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.URL; -import java.util.Properties; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.process.NetworkUtilsImpl; -import org.sonar.process.Props; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -public class EmbeddedTomcatTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Test - public void start() throws Exception { - Props props = new Props(new Properties()); - - // prepare file system - File home = temp.newFolder(); - File data = temp.newFolder(); - File webDir = new File(home, "web"); - FileUtils.write(new File(home, "web/WEB-INF/web.xml"), "<web-app/>"); - props.set("sonar.path.home", home.getAbsolutePath()); - props.set("sonar.path.data", data.getAbsolutePath()); - props.set("sonar.path.web", webDir.getAbsolutePath()); - props.set("sonar.path.logs", temp.newFolder().getAbsolutePath()); - - // start server on a random port - InetAddress address = InetAddress.getLoopbackAddress(); - int httpPort = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(address); - props.set("sonar.web.host", address.getHostAddress()); - props.set("sonar.web.port", String.valueOf(httpPort)); - EmbeddedTomcat tomcat = new EmbeddedTomcat(props); - assertThat(tomcat.getStatus()).isEqualTo(EmbeddedTomcat.Status.DOWN); - tomcat.start(); - assertThat(tomcat.getStatus()).isEqualTo(EmbeddedTomcat.Status.UP); - - // check that http connector accepts requests - URL url = new URL("http://" + address.getHostAddress() + ":" + httpPort); - url.openConnection().connect(); - - // stop server - tomcat.terminate(); - // tomcat.isUp() must not be called. It is used to wait for server startup, not shutdown. - try { - url.openConnection().connect(); - fail(); - } catch (ConnectException e) { - // expected - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/NullJarScannerTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/NullJarScannerTest.java deleted file mode 100644 index de2919ca2ef..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/NullJarScannerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import org.apache.tomcat.JarScanFilter; -import org.apache.tomcat.JarScanType; -import org.apache.tomcat.JarScannerCallback; -import org.junit.Test; - -import javax.servlet.ServletContext; - -import static org.assertj.core.api.Assertions.assertThat; -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); - JarScannerCallback callback = mock(JarScannerCallback.class); - - NullJarScanner scanner = new NullJarScanner(); - - scanner.scan(JarScanType.PLUGGABILITY, context, callback); - verifyZeroInteractions(context, callback); - scanner.setJarScanFilter(mock(JarScanFilter.class)); - assertThat(scanner.getJarScanFilter()).isNull(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/ProgrammaticLogbackValveTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/ProgrammaticLogbackValveTest.java deleted file mode 100644 index fe5f4121e11..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/ProgrammaticLogbackValveTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import org.apache.catalina.Container; -import org.junit.AfterClass; -import org.junit.Test; -import org.sonar.process.logging.LogbackHelper; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -public class ProgrammaticLogbackValveTest { - - @AfterClass - public static void resetLogback() throws Exception { - new LogbackHelper().resetFromXml("/logback-test.xml"); - } - - @Test - public void startInternal() throws Exception { - ProgrammaticLogbackValve valve = new ProgrammaticLogbackValve(); - valve.setContainer(mock(Container.class)); - - valve.start(); - assertThat(valve.isStarted()).isTrue(); - - valve.stop(); - assertThat(valve.isStarted()).isFalse(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/StartupLogsTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/StartupLogsTest.java deleted file mode 100644 index e0d26e33749..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/StartupLogsTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import org.apache.catalina.connector.Connector; -import org.apache.catalina.startup.Tomcat; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.api.utils.log.Logger; - -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -public class StartupLogsTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); - private Logger logger = mock(Logger.class); - private TomcatStartupLogs underTest = new TomcatStartupLogs(logger); - - @Test - public void fail_with_IAE_on_unsupported_protocol() { - Connector connector = newConnector("AJP/1.3", "ajp"); - when(tomcat.getService().findConnectors()).thenReturn(new Connector[] {connector}); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Unsupported connector: Connector[AJP/1.3-1234]"); - - underTest.log(tomcat); - } - - @Test - public void logHttp() { - Connector connector = newConnector("HTTP/1.1", "http"); - when(tomcat.getService().findConnectors()).thenReturn(new Connector[] {connector}); - - underTest.log(tomcat); - - verify(logger).info("HTTP connector enabled on port 1234"); - verifyNoMoreInteractions(logger); - } - - @Test - public void unsupported_connector() { - Connector connector = mock(Connector.class, Mockito.RETURNS_DEEP_STUBS); - when(connector.getProtocol()).thenReturn("SPDY/1.1"); - when(connector.getScheme()).thenReturn("spdy"); - when(tomcat.getService().findConnectors()).thenReturn(new Connector[] {connector}); - try { - underTest.log(tomcat); - fail(); - } catch (IllegalArgumentException e) { - // expected - } - } - - private Connector newConnector(String protocol, String schema) { - Connector httpConnector = new Connector(protocol); - httpConnector.setScheme(schema); - httpConnector.setPort(1234); - return httpConnector; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatAccessLogTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/TomcatAccessLogTest.java deleted file mode 100644 index 750c77ce376..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatAccessLogTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.startup.Tomcat; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.mockito.Mockito; -import org.sonar.api.utils.log.Logger; -import org.sonar.process.Props; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.sonar.process.ProcessProperties.Property.PATH_LOGS; - -public class TomcatAccessLogTest { - - TomcatAccessLog underTest = new TomcatAccessLog(); - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Before - public void setHome() throws IOException { - File homeDir = temp.newFolder("home"); - System.setProperty("SONAR_HOME", homeDir.getAbsolutePath()); - } - - @Test - public void enable_access_logs_by_Default() throws Exception { - Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); - Props props = new Props(new Properties()); - props.set(PATH_LOGS.getKey(), temp.newFolder().getAbsolutePath()); - underTest.configure(tomcat, props); - - verify(tomcat.getHost().getPipeline()).addValve(any(ProgrammaticLogbackValve.class)); - } - - @Test - public void log_when_started_and_stopped() { - Logger logger = mock(Logger.class); - TomcatAccessLog.LifecycleLogger listener = new TomcatAccessLog.LifecycleLogger(logger); - - LifecycleEvent event = new LifecycleEvent(mock(Lifecycle.class), "before_init", null); - listener.lifecycleEvent(event); - verifyZeroInteractions(logger); - - event = new LifecycleEvent(mock(Lifecycle.class), "after_start", null); - listener.lifecycleEvent(event); - verify(logger).debug("Tomcat is started"); - - event = new LifecycleEvent(mock(Lifecycle.class), "after_destroy", null); - listener.lifecycleEvent(event); - verify(logger).debug("Tomcat is stopped"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatConnectorsTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/TomcatConnectorsTest.java deleted file mode 100644 index 27035ac9480..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatConnectorsTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import com.google.common.collect.ImmutableMap; -import java.net.InetAddress; -import java.util.Map; -import java.util.Properties; -import org.apache.catalina.startup.Tomcat; -import org.junit.Test; -import org.mockito.Mockito; -import org.sonar.process.Props; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class TomcatConnectorsTest { - - private static final int DEFAULT_PORT = 9000; - private Tomcat tomcat = mock(Tomcat.class, Mockito.RETURNS_DEEP_STUBS); - - @Test - public void configure_thread_pool() { - Properties p = new Properties(); - p.setProperty("sonar.web.http.minThreads", "2"); - p.setProperty("sonar.web.http.maxThreads", "30"); - p.setProperty("sonar.web.http.acceptCount", "20"); - Props props = new Props(p); - - TomcatConnectors.configure(tomcat, props); - - verifyHttpConnector(DEFAULT_PORT, ImmutableMap.of("minSpareThreads", 2, "maxThreads", 30, "acceptCount", 20)); - } - - @Test - public void configure_defaults() { - Props props = new Props(new Properties()); - - TomcatConnectors.configure(tomcat, props); - - verifyHttpConnector(DEFAULT_PORT, ImmutableMap.of("minSpareThreads", 5, "maxThreads", 50, "acceptCount", 25)); - } - - @Test - public void different_thread_pools_for_connectors() { - Properties p = new Properties(); - p.setProperty("sonar.web.http.minThreads", "2"); - Props props = new Props(p); - - TomcatConnectors.configure(tomcat, props); - - verifyHttpConnector(DEFAULT_PORT, ImmutableMap.of("minSpareThreads", 2)); - } - - @Test - public void fail_with_ISE_if_http_port_is_invalid() { - Properties p = new Properties(); - p.setProperty("sonar.web.port", "-1"); - - try { - TomcatConnectors.configure(tomcat, new Props(p)); - fail(); - } catch (IllegalStateException e) { - assertThat(e).hasMessage("HTTP port '-1' is invalid"); - } - } - - @Test - public void bind_to_all_addresses_by_default() { - Properties p = new Properties(); - p.setProperty("sonar.web.port", "9000"); - - TomcatConnectors.configure(tomcat, new Props(p)); - - verify(tomcat.getService()).addConnector(argThat(c -> c.getScheme().equals("http") && c.getPort() == 9000 && ((InetAddress) c.getProperty("address")).getHostAddress().equals("0.0.0.0"))); - } - - @Test - public void bind_to_specific_address() { - Properties p = new Properties(); - p.setProperty("sonar.web.port", "9000"); - p.setProperty("sonar.web.host", "1.2.3.4"); - - TomcatConnectors.configure(tomcat, new Props(p)); - - verify(tomcat.getService()) - .addConnector(argThat(c -> c.getScheme().equals("http") && c.getPort() == 9000 && ((InetAddress) c.getProperty("address")).getHostAddress().equals("1.2.3.4"))); - } - - @Test - public void test_max_http_header_size_for_http_connection() { - TomcatConnectors.configure(tomcat, new Props(new Properties())); - - verifyHttpConnector(DEFAULT_PORT, ImmutableMap.of("maxHttpHeaderSize", TomcatConnectors.MAX_HTTP_HEADER_SIZE_BYTES)); - } - - @Test - public void test_max_post_size_for_http_connection() { - Properties properties = new Properties(); - - Props props = new Props(properties); - TomcatConnectors.configure(tomcat, props); - verify(tomcat.getService()).addConnector(argThat(c -> c.getMaxPostSize() == -1)); - } - - private void verifyHttpConnector(int expectedPort, Map<String, Object> expectedProps) { - verify(tomcat.getService()).addConnector(argThat(c -> { - if (!c.getScheme().equals("http")) { - return false; - } - if (!c.getProtocol().equals(TomcatConnectors.HTTP_PROTOCOL)) { - return false; - } - if (c.getPort() != expectedPort) { - return false; - } - for (Map.Entry<String, Object> expectedProp : expectedProps.entrySet()) { - if (!expectedProp.getValue().equals(c.getProperty(expectedProp.getKey()))) { - return false; - } - } - return true; - })); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatContextsTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/TomcatContextsTest.java deleted file mode 100644 index b9a0c808d61..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/app/TomcatContextsTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.app; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.startup.Tomcat; -import org.apache.commons.io.FileUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.utils.MessageException; -import org.sonar.process.Props; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.sonar.process.ProcessProperties.Property; - -public class TomcatContextsTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - Tomcat tomcat = mock(Tomcat.class); - - Properties props = new Properties(); - TomcatContexts underTest = new TomcatContexts(); - - @Before - public void setUp() throws Exception { - props.setProperty(Property.PATH_DATA.getKey(), temp.newFolder("data").getAbsolutePath()); - when(tomcat.addWebapp(anyString(), anyString())).thenReturn(mock(StandardContext.class)); - } - - @Test - public void configure_root_webapp() throws Exception { - props.setProperty("foo", "bar"); - StandardContext context = mock(StandardContext.class); - when(tomcat.addWebapp(anyString(), anyString())).thenReturn(context); - - underTest.configure(tomcat, new Props(props)); - - // configure webapp with properties - verify(context).addParameter("foo", "bar"); - } - - @Test - public void create_dir_and_configure_static_directory() throws Exception { - File dir = temp.newFolder(); - dir.delete(); - - underTest.addStaticDir(tomcat, "/deploy", dir); - - assertThat(dir).isDirectory().exists(); - verify(tomcat).addWebapp("/deploy", dir.getAbsolutePath()); - } - - @Test - public void cleanup_static_directory_if_already_exists() throws Exception { - File dir = temp.newFolder(); - FileUtils.touch(new File(dir, "foo.txt")); - - underTest.addStaticDir(tomcat, "/deploy", dir); - - assertThat(dir).isDirectory().exists(); - assertThat(dir.listFiles()).isEmpty(); - } - - @Test - public void fail_if_static_directory_can_not_be_initialized() throws Exception { - File dir = temp.newFolder(); - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Fail to create or clean-up directory " + dir.getAbsolutePath()); - - TomcatContexts.Fs fs = mock(TomcatContexts.Fs.class); - doThrow(new IOException()).when(fs).createOrCleanupDir(any(File.class)); - - new TomcatContexts(fs).addStaticDir(tomcat, "/deploy", dir); - } - - @Test - public void context_path() { - props.setProperty("sonar.web.context", "/foo"); - - assertThat(TomcatContexts.getContextPath(new Props(props))).isEqualTo("/foo"); - } - - @Test - public void context_path_must_start_with_slash() { - props.setProperty("sonar.web.context", "foo"); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Value of 'sonar.web.context' must start with a forward slash: 'foo'"); - underTest.configure(tomcat, new Props(props)); - } - - @Test - public void root_context_path_must_be_blank() { - props.setProperty("sonar.web.context", "/"); - - assertThat(TomcatContexts.getContextPath(new Props(props))).isEqualTo(""); - } - - @Test - public void default_context_path_is_root() { - String context = TomcatContexts.getContextPath(new Props(new Properties())); - assertThat(context).isEqualTo(""); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel1Test.java b/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel1Test.java deleted file mode 100644 index 7bed9b1f319..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel1Test.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.util.Properties; -import org.junit.Test; -import org.sonar.api.config.PropertyDefinition; -import org.sonar.api.utils.System2; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.WebServer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - - -public class PlatformLevel1Test { - - private PlatformLevel1 underTest = new PlatformLevel1(mock(Platform.class), new Properties()); - - @Test - public void no_missing_dependencies_between_components() { - underTest.configureLevel(); - - assertThat(underTest.getAll(PropertyDefinition.class)).isNotEmpty(); - assertThat(underTest.getOptional(WebServer.class)).isPresent(); - assertThat(underTest.getOptional(System2.class)).isPresent(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel2Test.java b/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel2Test.java deleted file mode 100644 index f196aa6f135..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel2Test.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.util.Properties; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.utils.System2; -import org.sonar.core.platform.PluginRepository; -import org.sonar.server.platform.Platform; -import org.sonar.server.platform.WebServer; -import org.sonar.server.platform.db.migration.charset.DatabaseCharsetChecker; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.sonar.process.ProcessProperties.Property.PATH_DATA; -import static org.sonar.process.ProcessProperties.Property.PATH_HOME; -import static org.sonar.process.ProcessProperties.Property.PATH_TEMP; - -public class PlatformLevel2Test { - - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); - - private Properties props = new Properties(); - - @Before - public void setUp() throws Exception { - // these are mandatory settings declared by bootstrap process - props.setProperty(PATH_HOME.getKey(), tempFolder.newFolder().getAbsolutePath()); - props.setProperty(PATH_DATA.getKey(), tempFolder.newFolder().getAbsolutePath()); - props.setProperty(PATH_TEMP.getKey(), tempFolder.newFolder().getAbsolutePath()); - } - - @Test - public void add_all_components_by_default() { - PlatformLevel1 level1 = new PlatformLevel1(mock(Platform.class), props); - level1.configure(); - - PlatformLevel2 underTest = new PlatformLevel2(level1); - underTest.configure(); - - // some level1 components - assertThat(underTest.getOptional(WebServer.class)).isPresent(); - assertThat(underTest.getOptional(System2.class)).isPresent(); - - // level2 component that does not depend on cluster state - assertThat(underTest.getOptional(PluginRepository.class)).isPresent(); - - // level2 component that is injected only on "startup leaders" - assertThat(underTest.getOptional(DatabaseCharsetChecker.class)).isPresent(); - } - - @Test - public void do_not_add_all_components_when_startup_follower() { - props.setProperty("sonar.cluster.enabled", "true"); - PlatformLevel1 level1 = new PlatformLevel1(mock(Platform.class), props); - level1.configure(); - - PlatformLevel2 underTest = new PlatformLevel2(level1); - underTest.configure(); - - assertThat(underTest.get(WebServer.class).isStartupLeader()).isFalse(); - - // level2 component that does not depend on cluster state - assertThat(underTest.getOptional(PluginRepository.class)).isPresent(); - - // level2 component that is injected only on "startup leaders" - assertThat(underTest.getOptional(DatabaseCharsetChecker.class)).isNotPresent(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevelTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevelTest.java deleted file mode 100644 index b3d70118df1..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevelTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.platformlevel; - -import java.util.Random; -import java.util.stream.IntStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.server.platform.WebServer; - -import static org.assertj.core.api.Assertions.assertThat; - -public class PlatformLevelTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private PlatformLevel underTest = new PlatformLevel("name") { - - @Override - protected void configureLevel() { - - } - }; - - @Test - public void addIfStartupLeader_throws_ISE_if_container_does_not_have_WebServer_object() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("WebServer not available in Pico yet"); - - underTest.addIfStartupLeader(); - } - - @Test - public void addIfStartupLeader_always_returns_the_same_instance() { - underTest.add(Mockito.mock(WebServer.class)); - - PlatformLevel.AddIfStartupLeader addIfStartupLeader = underTest.addIfStartupLeader(); - IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfStartupLeader()).isSameAs(addIfStartupLeader)); - } - - @Test - public void addIfCluster_throws_ISE_if_container_does_not_have_WebServer_object() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("WebServer not available in Pico yet"); - - underTest.addIfCluster(); - } - - @Test - public void addIfCluster_always_returns_the_same_instance() { - underTest.add(Mockito.mock(WebServer.class)); - - PlatformLevel.AddIfCluster addIfCluster = underTest.addIfCluster(); - IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfCluster()).isSameAs(addIfCluster)); - } - - @Test - public void addIfStandalone_throws_ISE_if_container_does_not_have_WebServer_object() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("WebServer not available in Pico yet"); - - underTest.addIfCluster(); - } - - @Test - public void addIfStandalone_always_returns_the_same_instance() { - underTest.add(Mockito.mock(WebServer.class)); - - PlatformLevel.AddIfCluster addIfCluster = underTest.addIfCluster(); - IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfCluster()).isSameAs(addIfCluster)); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/CacheControlFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/CacheControlFilterTest.java deleted file mode 100644 index 5b541f9e859..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/CacheControlFilterTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import javax.servlet.FilterChain; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Test; - -import static java.lang.String.format; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class CacheControlFilterTest { - - private HttpServletResponse response = mock(HttpServletResponse.class); - private FilterChain chain = mock(FilterChain.class); - - private CacheControlFilter underTest = new CacheControlFilter(); - - @Test - public void max_age_is_set_to_one_year_on_js() throws Exception { - HttpServletRequest request = newRequest("/js/sonar.js"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("Cache-Control", format("max-age=%s", 31_536_000)); - } - - @Test - public void max_age_is_set_to_one_year_on_css() throws Exception { - HttpServletRequest request = newRequest("/css/sonar.css"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("Cache-Control", format("max-age=%s", 31_536_000)); - } - - @Test - public void max_age_is_set_to_five_minutes_on_images() throws Exception { - HttpServletRequest request = newRequest("/images/logo.png"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("Cache-Control", format("max-age=%s", 300)); - } - - @Test - public void max_age_is_set_to_five_minutes_on_static() throws Exception { - HttpServletRequest request = newRequest("/static/something"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("Cache-Control", format("max-age=%s", 300)); - } - - @Test - public void max_age_is_set_to_five_minutes_on_css_of_static() throws Exception { - HttpServletRequest request = newRequest("/static/css/custom.css"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("Cache-Control", format("max-age=%s", 300)); - } - - @Test - public void does_nothing_on_home() throws Exception { - HttpServletRequest request = newRequest("/"); - - underTest.doFilter(request, response, chain); - - verifyZeroInteractions(response); - } - - @Test - public void does_nothing_on_web_service() throws Exception { - HttpServletRequest request = newRequest("/api/ping"); - - underTest.doFilter(request, response, chain); - - verifyZeroInteractions(response); - } - - private static HttpServletRequest newRequest(String path) { - HttpServletRequest req = mock(HttpServletRequest.class); - when(req.getMethod()).thenReturn("GET"); - when(req.getRequestURI()).thenReturn(path); - when(req.getContextPath()).thenReturn(""); - return req; - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/MasterServletFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/MasterServletFilterTest.java deleted file mode 100644 index 3999670c143..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/MasterServletFilterTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.io.IOException; -import java.util.Collections; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.api.web.ServletFilter; -import org.sonar.api.web.ServletFilter.UrlPattern; - -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class MasterServletFilterTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public LogTester logTester = new LogTester(); - - @Before - public void resetSingleton() { - MasterServletFilter.INSTANCE = null; - } - - @Test - public void should_init_and_destroy_filters() throws Exception { - ServletFilter filter = createMockFilter(); - FilterConfig config = mock(FilterConfig.class); - MasterServletFilter master = new MasterServletFilter(); - master.init(config, singletonList(filter)); - - assertThat(master.getFilters()).containsOnly(filter); - verify(filter).init(config); - - master.destroy(); - verify(filter).destroy(); - } - - @Test - public void servlet_container_should_instantiate_only_a_single_master_instance() { - new MasterServletFilter(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Servlet filter org.sonar.server.platform.web.MasterServletFilter is already instantiated"); - new MasterServletFilter(); - } - - @Test - public void should_propagate_initialization_failure() throws Exception { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("foo"); - - ServletFilter filter = createMockFilter(); - doThrow(new IllegalStateException("foo")).when(filter).init(any(FilterConfig.class)); - - FilterConfig config = mock(FilterConfig.class); - MasterServletFilter filters = new MasterServletFilter(); - filters.init(config, singletonList(filter)); - } - - @Test - public void filters_should_be_optional() throws Exception { - FilterConfig config = mock(FilterConfig.class); - MasterServletFilter filters = new MasterServletFilter(); - filters.init(config, Collections.emptyList()); - - ServletRequest request = mock(HttpServletRequest.class); - ServletResponse response = mock(HttpServletResponse.class); - FilterChain chain = mock(FilterChain.class); - filters.doFilter(request, response, chain); - - verify(chain).doFilter(request, response); - } - - @Test - public void should_keep_filter_ordering() throws Exception { - TrueFilter filter1 = new TrueFilter(); - TrueFilter filter2 = new TrueFilter(); - - MasterServletFilter filters = new MasterServletFilter(); - filters.init(mock(FilterConfig.class), asList(filter1, filter2)); - - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getRequestURI()).thenReturn("/foo/bar"); - when(request.getContextPath()).thenReturn(""); - ServletResponse response = mock(HttpServletResponse.class); - FilterChain chain = mock(FilterChain.class); - filters.doFilter(request, response, chain); - - assertThat(filter1.count).isEqualTo(1); - assertThat(filter2.count).isEqualTo(2); - } - - @Test - public void display_servlet_filter_patterns_in_INFO_log() throws Exception { - ServletFilter filter = new PatternFilter(UrlPattern.builder().includes("/api/issues").excludes("/batch/projects").build()); - FilterConfig config = mock(FilterConfig.class); - MasterServletFilter master = new MasterServletFilter(); - - master.init(config, singletonList(filter)); - - assertThat(logTester.logs(LoggerLevel.INFO)).containsOnly("Initializing servlet filter PatternFilter [pattern=UrlPattern{inclusions=[/api/issues], exclusions=[/batch/projects]}]"); - } - - private static ServletFilter createMockFilter() { - ServletFilter filter = mock(ServletFilter.class); - when(filter.doGetPattern()).thenReturn(UrlPattern.builder().build()); - return filter; - } - - private static final class TrueFilter extends ServletFilter { - private static int globalCount = 0; - private int count = 0; - - @Override - public void init(FilterConfig filterConfig) { - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - globalCount++; - count = globalCount; - filterChain.doFilter(servletRequest, servletResponse); - } - - @Override - public void destroy() { - } - } - - private static class PatternFilter extends ServletFilter { - - private final UrlPattern urlPattern; - - PatternFilter(UrlPattern urlPattern) { - this.urlPattern = urlPattern; - } - - @Override - public UrlPattern doGetPattern() { - return urlPattern; - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) { - // Nothing to do - } - - @Override - public void init(FilterConfig filterConfig) { - // Nothing to do - } - - @Override - public void destroy() { - // Nothing to do - } - - @Override - public String toString() { - return "PatternFilter"; - } - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/RedirectFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/RedirectFilterTest.java deleted file mode 100644 index 255e97509cc..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/RedirectFilterTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.io.IOException; -import javax.annotation.Nullable; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Test; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class RedirectFilterTest { - - private HttpServletRequest request = mock(HttpServletRequest.class); - private HttpServletResponse response = mock(HttpServletResponse.class); - private FilterChain chain = mock(FilterChain.class); - - private RedirectFilter underTest = new RedirectFilter(); - - @Before - public void setUp() throws Exception { - when(request.getContextPath()).thenReturn("/sonarqube"); - } - - @Test - public void send_redirect_when_url_contains_only_api() throws Exception { - verifyRedirection("/api", null, "/sonarqube/api/webservices/list"); - verifyRedirection("/api/", null, "/sonarqube/api/webservices/list"); - } - - @Test - public void does_not_redirect_and_execute_remaining_filter_on_unknown_path() throws Exception { - verifyNoRedirection("/api/issues/search", null); - } - - private void verifyRedirection(String requestUrl, @Nullable String queryString, String expectedRedirection) throws Exception { - when(request.getRequestURI()).thenReturn(requestUrl); - when(request.getQueryString()).thenReturn(queryString); - - underTest.doFilter(request, response, chain); - - verify(response).sendRedirect(expectedRedirection); - verifyZeroInteractions(chain); - reset(response, chain); - } - - private void verifyNoRedirection(String requestUrl, @Nullable String queryString) throws IOException, ServletException { - when(request.getRequestURI()).thenReturn(requestUrl); - when(request.getQueryString()).thenReturn(queryString); - when(request.getParameter(anyString())).thenReturn(null); - - underTest.doFilter(request, response, chain); - - verify(chain).doFilter(request, response); - verifyZeroInteractions(response); - reset(response, chain); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/RootFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/RootFilterTest.java deleted file mode 100644 index e700d9983a8..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/RootFilterTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.util.List; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class RootFilterTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Rule - public LogTester logTester = new LogTester(); - - private FilterChain chain = mock(FilterChain.class); - private RootFilter underTest; - - @Before - public void initialize() { - FilterConfig filterConfig = mock(FilterConfig.class); - ServletContext context = mock(ServletContext.class); - when(context.getContextPath()).thenReturn("/context"); - when(filterConfig.getServletContext()).thenReturn(context); - underTest = new RootFilter(); - underTest.init(filterConfig); - } - - @Test - public void throwable_in_doFilter_is_caught_and_500_error_returned_if_response_is_not_committed() throws Exception { - doThrow(new RuntimeException()).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class)); - HttpServletResponse response = mockHttpResponse(false); - underTest.doFilter(request("POST", "/context/service/call", "param=value"), response, chain); - - verify(response).sendError(500); - } - - @Test - public void throwable_in_doFilter_is_caught_but_no_500_response_is_sent_if_response_already_committed() throws Exception { - doThrow(new RuntimeException()).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class)); - HttpServletResponse response = mockHttpResponse(true); - underTest.doFilter(request("POST", "/context/service/call", "param=value"), response, chain); - - verify(response, never()).sendError(500); - } - - @Test - public void throwable_in_doFilter_is_logged_in_debug_if_response_is_already_committed() throws Exception { - doThrow(new RuntimeException()).when(chain).doFilter(any(ServletRequest.class), any(ServletResponse.class)); - HttpServletResponse response = mockHttpResponse(true); - underTest.doFilter(request("POST", "/context/service/call", "param=value"), response, chain); - - List<String> debugLogs = logTester.logs(LoggerLevel.DEBUG); - assertThat(debugLogs.size()).isEqualTo(1); - assertThat(debugLogs.get(0)).contains("Processing of request", "failed"); - } - - - @Test - public void request_used_in_chain_do_filter_is_a_servlet_wrapper_when_static_resource() throws Exception { - underTest.doFilter(request("GET", "/context/static/image.png", null), mock(HttpServletResponse.class), chain); - ArgumentCaptor<ServletRequest> requestArgumentCaptor = ArgumentCaptor.forClass(ServletRequest.class); - - verify(chain).doFilter(requestArgumentCaptor.capture(), any(HttpServletResponse.class)); - - assertThat(requestArgumentCaptor.getValue()).isInstanceOf(RootFilter.ServletRequestWrapper.class); - } - - @Test - public void request_used_in_chain_do_filter_is_a_servlet_wrapper_when_service_call() throws Exception { - underTest.doFilter(request("POST", "/context/service/call", "param=value"), mock(HttpServletResponse.class), chain); - ArgumentCaptor<ServletRequest> requestArgumentCaptor = ArgumentCaptor.forClass(ServletRequest.class); - - verify(chain).doFilter(requestArgumentCaptor.capture(), any(HttpServletResponse.class)); - - assertThat(requestArgumentCaptor.getValue()).isInstanceOf(RootFilter.ServletRequestWrapper.class); - } - - @Test - public void fail_to_get_session_from_request() throws Exception { - underTest.doFilter(request("GET", "/context/static/image.png", null), mock(HttpServletResponse.class), chain); - ArgumentCaptor<ServletRequest> requestArgumentCaptor = ArgumentCaptor.forClass(ServletRequest.class); - verify(chain).doFilter(requestArgumentCaptor.capture(), any(ServletResponse.class)); - - expectedException.expect(UnsupportedOperationException.class); - ((HttpServletRequest) requestArgumentCaptor.getValue()).getSession(); - } - - @Test - public void fail_to_get_session_with_create_from_request() throws Exception { - underTest.doFilter(request("GET", "/context/static/image.png", null), mock(HttpServletResponse.class), chain); - ArgumentCaptor<ServletRequest> requestArgumentCaptor = ArgumentCaptor.forClass(ServletRequest.class); - verify(chain).doFilter(requestArgumentCaptor.capture(), any(ServletResponse.class)); - - expectedException.expect(UnsupportedOperationException.class); - ((HttpServletRequest) requestArgumentCaptor.getValue()).getSession(true); - } - - private HttpServletRequest request(String method, String path, String query) { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getMethod()).thenReturn(method); - when(request.getRequestURI()).thenReturn(path); - when(request.getQueryString()).thenReturn(query); - return request; - } - - private static HttpServletResponse mockHttpResponse(boolean committed) { - HttpServletResponse response = mock(HttpServletResponse.class); - when(response.isCommitted()).thenReturn(committed); - return response; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/SecurityServletFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/SecurityServletFilterTest.java deleted file mode 100644 index e01eb8947ee..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/SecurityServletFilterTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Test; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class SecurityServletFilterTest { - - private SecurityServletFilter underTest = new SecurityServletFilter(); - private HttpServletResponse response = mock(HttpServletResponse.class); - private FilterChain chain = mock(FilterChain.class); - - @Test - public void allow_GET_method() throws IOException, ServletException { - assertThatMethodIsAllowed("GET"); - } - - @Test - public void allow_HEAD_method() throws IOException, ServletException { - assertThatMethodIsAllowed("HEAD"); - } - - @Test - public void allow_PUT_method() throws IOException, ServletException { - assertThatMethodIsAllowed("PUT"); - } - - @Test - public void allow_POST_method() throws IOException, ServletException { - assertThatMethodIsAllowed("POST"); - } - - private void assertThatMethodIsAllowed(String httpMethod) throws IOException, ServletException { - HttpServletRequest request = newRequest(httpMethod, "/"); - underTest.doFilter(request, response, chain); - verify(response, never()).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - verify(chain).doFilter(request, response); - } - - @Test - public void deny_OPTIONS_method() throws IOException, ServletException { - assertThatMethodIsDenied("OPTIONS"); - } - - @Test - public void deny_TRACE_method() throws IOException, ServletException { - assertThatMethodIsDenied("TRACE"); - } - - private void assertThatMethodIsDenied(String httpMethod) throws IOException, ServletException { - underTest.doFilter(newRequest(httpMethod, "/"), response, chain); - verify(response).setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - } - - @Test - public void set_security_headers() throws Exception { - HttpServletRequest request = newRequest("GET", "/"); - - underTest.doFilter(request, response, chain); - - verify(response).addHeader("X-Frame-Options", "SAMEORIGIN"); - verify(response).addHeader("X-XSS-Protection", "1; mode=block"); - verify(response).addHeader("X-Content-Type-Options", "nosniff"); - } - - @Test - public void do_not_set_frame_protection_on_integration_resources() throws Exception { - HttpServletRequest request = newRequest("GET", "/integration/vsts/index.html"); - - underTest.doFilter(request, response, chain); - - verify(response, never()).addHeader(eq("X-Frame-Options"), anyString()); - verify(response).addHeader("X-XSS-Protection", "1; mode=block"); - verify(response).addHeader("X-Content-Type-Options", "nosniff"); - } - - @Test - public void do_not_set_frame_protection_on_integration_resources_with_context() throws Exception { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getMethod()).thenReturn("GET"); - when(request.getRequestURI()).thenReturn("/sonarqube/integration/vsts/index.html"); - when(request.getContextPath()).thenReturn("/sonarqube"); - - underTest.doFilter(request, response, chain); - - verify(response, never()).addHeader(eq("X-Frame-Options"), anyString()); - verify(response).addHeader("X-XSS-Protection", "1; mode=block"); - verify(response).addHeader("X-Content-Type-Options", "nosniff"); - } - - private static HttpServletRequest newRequest(String httpMethod, String path) { - HttpServletRequest req = mock(HttpServletRequest.class); - when(req.getMethod()).thenReturn(httpMethod); - when(req.getRequestURI()).thenReturn(path); - when(req.getContextPath()).thenReturn(""); - return req; - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesCacheTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesCacheTest.java deleted file mode 100644 index 5551c269c15..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesCacheTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import java.io.InputStream; -import javax.servlet.ServletContext; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.stubbing.Answer; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.server.platform.OfficialDistribution; -import org.sonar.server.platform.Platform; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.commons.io.IOUtils.toInputStream; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.server.platform.Platform.Status.BOOTING; -import static org.sonar.server.platform.Platform.Status.STARTING; -import static org.sonar.server.platform.Platform.Status.UP; - -public class WebPagesCacheTest { - - private static final String TEST_CONTEXT = "/sonarqube"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ServletContext servletContext = mock(ServletContext.class); - - private OfficialDistribution officialDistribution = mock(OfficialDistribution.class); - private Platform platform = mock(Platform.class); - private MapSettings mapSettings = new MapSettings(); - - private WebPagesCache underTest = new WebPagesCache(platform, mapSettings.asConfig(), officialDistribution); - - @Before - public void setUp() throws Exception { - when(servletContext.getContextPath()).thenReturn(TEST_CONTEXT); - when(servletContext.getResourceAsStream("/index.html")).thenAnswer( - (Answer<InputStream>) invocationOnMock -> toInputStream("Content of default index.html with context [%WEB_CONTEXT%], status [%SERVER_STATUS%], instance [%INSTANCE%]", - UTF_8)); - when(servletContext.getResourceAsStream("/integration/vsts/index.html")) - .thenAnswer((Answer<InputStream>) invocationOnMock -> toInputStream("Content of vsts index.html with context [%WEB_CONTEXT%]", UTF_8)); - } - - @Test - public void check_paths() { - doInit(); - when(platform.status()).thenReturn(UP); - - assertThat(underTest.getContent("/foo")).contains(TEST_CONTEXT).contains("default"); - assertThat(underTest.getContent("/foo.html")).contains(TEST_CONTEXT).contains("default"); - assertThat(underTest.getContent("/index")).contains(TEST_CONTEXT).contains("default"); - assertThat(underTest.getContent("/index.html")).contains(TEST_CONTEXT).contains("default"); - assertThat(underTest.getContent("/integration/vsts/index.html")).contains(TEST_CONTEXT).contains("vsts"); - } - - @Test - public void contains_web_context() { - doInit(); - - assertThat(underTest.getContent("/foo")) - .contains(TEST_CONTEXT); - } - - @Test - public void status_is_starting() { - doInit(); - when(platform.status()).thenReturn(STARTING); - - assertThat(underTest.getContent("/foo")) - .contains(STARTING.name()); - } - - @Test - public void status_is_up() { - doInit(); - when(platform.status()).thenReturn(UP); - - assertThat(underTest.getContent("/foo")) - .contains(UP.name()); - } - - @Test - public void no_sonarcloud_setting() { - doInit(); - - assertThat(underTest.getContent("/foo")) - .contains("SonarQube"); - } - - @Test - public void sonarcloud_setting_is_false() { - mapSettings.setProperty("sonar.sonarcloud.enabled", false); - doInit(); - - assertThat(underTest.getContent("/foo")) - .contains("SonarQube"); - } - - @Test - public void sonarcloud_setting_is_true() { - mapSettings.setProperty("sonar.sonarcloud.enabled", true); - doInit(); - - assertThat(underTest.getContent("/foo")) - .contains("SonarCloud"); - } - - @Test - public void content_is_updated_when_status_has_changed() { - doInit(); - when(platform.status()).thenReturn(STARTING); - assertThat(underTest.getContent("/foo")) - .contains(STARTING.name()); - - when(platform.status()).thenReturn(UP); - assertThat(underTest.getContent("/foo")) - .contains(UP.name()); - } - - @Test - public void content_is_not_updated_when_status_is_up() { - doInit(); - when(platform.status()).thenReturn(UP); - assertThat(underTest.getContent("/foo")) - .contains(UP.name()); - - when(platform.status()).thenReturn(STARTING); - assertThat(underTest.getContent("/foo")) - .contains(UP.name()); - } - - @Test - public void fail_to_get_content_when_init_has_not_been_called() { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("init has not been called"); - - underTest.getContent("/foo"); - } - - private void doInit() { - when(platform.status()).thenReturn(BOOTING); - underTest.init(servletContext); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesFilterTest.java deleted file mode 100644 index d2949b6afc8..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/WebPagesFilterTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web; - -import javax.servlet.FilterChain; -import javax.servlet.ServletContext; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.RETURNS_MOCKS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class WebPagesFilterTest { - - private static final String TEST_CONTEXT = "/sonarqube"; - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private ServletContext servletContext = mock(ServletContext.class, RETURNS_MOCKS); - private WebPagesCache webPagesCache = mock(WebPagesCache.class); - - private HttpServletRequest request = mock(HttpServletRequest.class); - private HttpServletResponse response = mock(HttpServletResponse.class); - private FilterChain chain = mock(FilterChain.class); - - private WebPagesFilter underTest = new WebPagesFilter(webPagesCache); - - @Before - public void setUp() throws Exception { - when(servletContext.getContextPath()).thenReturn(TEST_CONTEXT); - } - - @Test - public void return_web_page_content() throws Exception { - String path = "/index.html"; - when(webPagesCache.getContent(path)).thenReturn("test"); - when(request.getRequestURI()).thenReturn(path); - when(request.getContextPath()).thenReturn(TEST_CONTEXT); - StringOutputStream outputStream = new StringOutputStream(); - when(response.getOutputStream()).thenReturn(outputStream); - - underTest.doFilter(request, response, chain); - - verify(response).setContentType("text/html"); - verify(response).setCharacterEncoding("utf-8"); - verify(response).setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - assertThat(outputStream.toString()).isEqualTo("test"); - } - - @Test - public void does_nothing_when_static_resource() throws Exception{ - when(request.getRequestURI()).thenReturn("/static"); - when(request.getContextPath()).thenReturn(TEST_CONTEXT); - - underTest.doFilter(request, response, chain); - - verify(chain).doFilter(request, response); - verifyZeroInteractions(webPagesCache); - } - - class StringOutputStream extends ServletOutputStream { - private final StringBuilder buf = new StringBuilder(); - - StringOutputStream() { - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setWriteListener(WriteListener listener) { - - } - - public void write(byte[] b) { - this.buf.append(new String(b)); - } - - public void write(byte[] b, int off, int len) { - this.buf.append(new String(b, off, len)); - } - - public void write(int b) { - byte[] bytes = new byte[] {(byte) b}; - this.buf.append(new String(bytes)); - } - - public String toString() { - return this.buf.toString(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/web/requestid/RequestIdFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/web/requestid/RequestIdFilterTest.java deleted file mode 100644 index b119cf59424..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/web/requestid/RequestIdFilterTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.platform.web.requestid; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.MDC; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.server.platform.Platform; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class RequestIdFilterTest { - private Platform platform = mock(Platform.class); - private RequestIdGenerator requestIdGenerator = mock(RequestIdGenerator.class); - private ServletRequest servletRequest = mock(ServletRequest.class); - private ServletResponse servletResponse = mock(ServletResponse.class); - private FilterChain filterChain = mock(FilterChain.class); - private RequestIdFilter underTest = new RequestIdFilter(platform); - - @Before - public void setUp() throws Exception { - ComponentContainer container = new ComponentContainer(); - container.add(requestIdGenerator); - when(platform.getContainer()).thenReturn(container); - } - - @Test - public void filter_put_id_in_MDC_and_remove_it_after_chain_has_executed() throws IOException, ServletException { - String requestId = "request id"; - when(requestIdGenerator.generate()).thenReturn(requestId); - doAnswer(invocation -> assertThat(MDC.get("HTTP_REQUEST_ID")).isEqualTo(requestId)) - .when(filterChain) - .doFilter(servletRequest, servletResponse); - - underTest.doFilter(servletRequest, servletResponse, filterChain); - - assertThat(MDC.get("HTTP_REQUEST_ID")).isNull(); - } - - @Test - public void filter_put_id_in_MDC_and_remove_it_after_chain_throws_exception() throws IOException, ServletException { - RuntimeException exception = new RuntimeException("Simulating chain failing"); - String requestId = "request id"; - when(requestIdGenerator.generate()).thenReturn(requestId); - doAnswer(invocation -> { - assertThat(MDC.get("HTTP_REQUEST_ID")).isEqualTo(requestId); - throw exception; - }) - .when(filterChain) - .doFilter(servletRequest, servletResponse); - - try { - underTest.doFilter(servletRequest, servletResponse, filterChain); - fail("A runtime exception should have been raised"); - } catch (RuntimeException e) { - assertThat(e).isEqualTo(exception); - } finally { - assertThat(MDC.get("HTTP_REQUEST_ID")).isNull(); - } - } - - @Test - public void filter_adds_requestId_to_request_passed_on_to_chain() throws IOException, ServletException { - String requestId = "request id"; - when(requestIdGenerator.generate()).thenReturn(requestId); - - underTest.doFilter(servletRequest, servletResponse, filterChain); - - verify(servletRequest).setAttribute("ID", requestId); - } - - @Test - public void filter_does_not_fail_when_there_is_no_RequestIdGenerator_in_container() throws IOException, ServletException { - Platform platform = mock(Platform.class); - when(platform.getContainer()).thenReturn(new ComponentContainer()); - RequestIdFilter underTest = new RequestIdFilter(platform); - - underTest.doFilter(servletRequest, servletResponse, filterChain); - } - - @Test - public void filter_does_not_add_requestId_to_request_passed_on_to_chain_when_there_is_no_RequestIdGenerator_in_container() throws IOException, ServletException { - Platform platform = mock(Platform.class); - when(platform.getContainer()).thenReturn(new ComponentContainer()); - RequestIdFilter underTest = new RequestIdFilter(platform); - - underTest.doFilter(servletRequest, servletResponse, filterChain); - - verify(servletRequest, times(0)).setAttribute(anyString(), anyString()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/StaticResourcesServletTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/StaticResourcesServletTest.java deleted file mode 100644 index 84795711fb9..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/StaticResourcesServletTest.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.plugins; - -import java.io.IOException; -import java.io.InputStream; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import javax.servlet.http.HttpServletResponse; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.apache.catalina.connector.ClientAbortException; -import org.apache.commons.io.IOUtils; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.core.platform.PluginInfo; -import org.sonar.core.platform.PluginRepository; -import org.sonar.core.extension.CoreExtensionRepository; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class StaticResourcesServletTest { - - @Rule - public LogTester logTester = new LogTester(); - private Server jetty; - - private PluginRepository pluginRepository = mock(PluginRepository.class); - private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class); - private TestSystem system = new TestSystem(pluginRepository, coreExtensionRepository); - - @Before - public void setUp() throws Exception { - jetty = new Server(0); - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/"); - ServletHolder servletHolder = new ServletHolder(new StaticResourcesServlet(system)); - context.addServlet(servletHolder, "/static/*"); - jetty.setHandler(context); - jetty.start(); - } - - @After - public void tearDown() throws Exception { - if (jetty != null) { - jetty.stop(); - } - } - - private Response call(String path) throws Exception { - OkHttpClient client = new OkHttpClient(); - Request request = new Request.Builder() - .url(jetty.getURI().resolve(path).toString()) - .build(); - return client.newCall(request).execute(); - } - - @Test - public void return_content_if_exists_in_installed_plugin() throws Exception { - system.pluginStream = IOUtils.toInputStream("bar"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.txt"); - - assertThat(response.isSuccessful()).isTrue(); - assertThat(response.body().string()).isEqualTo("bar"); - assertThat(system.pluginResource).isEqualTo("static/foo.txt"); - } - - @Test - public void return_content_of_folder_of_installed_plugin() throws Exception { - system.pluginStream = IOUtils.toInputStream("bar"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo/bar.txt"); - - assertThat(response.isSuccessful()).isTrue(); - assertThat(response.body().string()).isEqualTo("bar"); - assertThat(system.pluginResource).isEqualTo("static/foo/bar.txt"); - } - - @Test - public void return_content_of_folder_of_installed_core_extension() throws Exception { - system.coreExtensionStream = IOUtils.toInputStream("bar"); - when(coreExtensionRepository.isInstalled("coreext")).thenReturn(true); - - Response response = call("/static/coreext/foo/bar.txt"); - - assertThat(response.isSuccessful()).isTrue(); - assertThat(response.body().string()).isEqualTo("bar"); - assertThat(system.coreExtensionResource).isEqualTo("static/foo/bar.txt"); - } - - @Test - public void return_content_of_folder_of_installed_core_extension_over_installed_plugin_in_case_of_key_conflict() throws Exception { - system.coreExtensionStream = IOUtils.toInputStream("bar of plugin"); - when(coreExtensionRepository.isInstalled("samekey")).thenReturn(true); - system.coreExtensionStream = IOUtils.toInputStream("bar of core extension"); - when(coreExtensionRepository.isInstalled("samekey")).thenReturn(true); - - Response response = call("/static/samekey/foo/bar.txt"); - - assertThat(response.isSuccessful()).isTrue(); - assertThat(response.body().string()).isEqualTo("bar of core extension"); - assertThat(system.pluginResource).isNull(); - assertThat(system.coreExtensionResource).isEqualTo("static/foo/bar.txt"); - } - - @Test - public void mime_type_is_set_on_response() throws Exception { - system.pluginStream = IOUtils.toInputStream("bar"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.header("Content-Type")).isEqualTo("text/css"); - assertThat(response.body().string()).isEqualTo("bar"); - } - - @Test - public void return_404_if_resource_not_found_in_installed_plugin() throws Exception { - system.pluginStream = null; - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(404); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty(); - } - - @Test - public void return_404_if_plugin_does_not_exist() throws Exception { - system.pluginStream = null; - when(pluginRepository.hasPlugin("myplugin")).thenReturn(false); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(404); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty(); - } - - @Test - public void return_resource_if_exists_in_requested_plugin() throws Exception { - system.pluginStream = IOUtils.toInputStream("bar"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - when(pluginRepository.getPluginInfo("myplugin")).thenReturn(new PluginInfo("myplugin")); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.isSuccessful()).isTrue(); - assertThat(response.body().string()).isEqualTo("bar"); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty(); - } - - @Test - public void do_not_fail_nor_log_ERROR_when_response_is_already_committed_and_plugin_does_not_exist() throws Exception { - system.pluginStream = null; - system.isCommitted = true; - when(pluginRepository.hasPlugin("myplugin")).thenReturn(false); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(200); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Response is committed. Cannot send error response code 404"); - } - - @Test - public void do_not_fail_nor_log_ERROR_when_sendError_throws_IOException_and_plugin_does_not_exist() throws Exception { - system.sendErrorException = new IOException("Simulating sendError throwing IOException"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(false); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(200); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Failed to send error code 404: java.io.IOException: Simulating sendError throwing IOException"); - } - - @Test - public void do_not_fail_nor_log_ERROR_when_response_is_already_committed_and_resource_does_not_exist_in_installed_plugin() throws Exception { - system.isCommitted = true; - system.pluginStream = null; - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(200); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.TRACE)).contains("Response is committed. Cannot send error response code 404"); - } - - @Test - public void do_not_fail_nor_log_not_attempt_to_send_error_if_ClientAbortException_is_raised() throws Exception { - system.pluginStreamException = new ClientAbortException("Simulating ClientAbortException"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(200); - assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); - assertThat(logTester.logs(LoggerLevel.TRACE)).contains( - "Client canceled loading resource [static/foo.css] from plugin [myplugin]: org.apache.catalina.connector.ClientAbortException: Simulating ClientAbortException"); - } - - @Test - public void do_not_fail_when_response_is_committed_after_other_error() throws Exception { - system.isCommitted = true; - system.pluginStreamException = new RuntimeException("Simulating a error"); - when(pluginRepository.hasPlugin("myplugin")).thenReturn(true); - - Response response = call("/static/myplugin/foo.css"); - - assertThat(response.code()).isEqualTo(200); - assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Unable to load resource [static/foo.css] from plugin [myplugin]"); - } - - private static class TestSystem extends StaticResourcesServlet.System { - private final PluginRepository pluginRepository; - private final CoreExtensionRepository coreExtensionRepository; - @Nullable - private InputStream pluginStream; - private Exception pluginStreamException = null; - @Nullable - private String pluginResource; - @Nullable - private InputStream coreExtensionStream; - private Exception coreExtensionStreamException = null; - private String coreExtensionResource; - private boolean isCommitted = false; - private IOException sendErrorException = null; - - TestSystem(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository) { - this.pluginRepository = pluginRepository; - this.coreExtensionRepository = coreExtensionRepository; - } - - @Override - PluginRepository getPluginRepository() { - return pluginRepository; - } - - @Override - CoreExtensionRepository getCoreExtensionRepository() { - return this.coreExtensionRepository; - } - - @CheckForNull - @Override - InputStream openPluginResourceStream(String pluginKey, String resource, PluginRepository pluginRepository) throws Exception { - pluginResource = resource; - if (pluginStreamException != null) { - throw pluginStreamException; - } - return pluginStream; - } - - @CheckForNull - @Override - InputStream openCoreExtensionResourceStream(String resource) throws Exception { - coreExtensionResource = resource; - if (coreExtensionStreamException != null) { - throw coreExtensionStreamException; - } - return coreExtensionStream; - } - - @Override - boolean isCommitted(HttpServletResponse response) { - return isCommitted; - } - - @Override - void sendError(HttpServletResponse response, int error) throws IOException { - if (sendErrorException != null) { - throw sendErrorException; - } else { - super.sendError(response, error); - } - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterServletFiltersTest.java b/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterServletFiltersTest.java deleted file mode 100644 index 0543dcdf32b..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterServletFiltersTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.startup; - -import javax.servlet.ServletException; -import org.junit.Test; -import org.sonar.api.web.ServletFilter; -import org.sonar.server.platform.web.MasterServletFilter; -import org.sonar.server.platform.web.RegisterServletFilters; - -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class RegisterServletFiltersTest { - @Test - public void should_not_fail_if_master_filter_is_not_up() throws ServletException { - MasterServletFilter.INSTANCE = null; - new RegisterServletFilters(new ServletFilter[2]).start(); - } - - @Test - public void should_register_filters_if_master_filter_is_up() throws ServletException { - MasterServletFilter.INSTANCE = mock(MasterServletFilter.class); - new RegisterServletFilters(new ServletFilter[2]).start(); - - verify(MasterServletFilter.INSTANCE).initFilters(anyList()); - } - - @Test - public void filters_should_be_optional() throws ServletException { - MasterServletFilter.INSTANCE = mock(MasterServletFilter.class); - new RegisterServletFilters().start(); - // do not fail - verify(MasterServletFilter.INSTANCE).initFilters(anyList()); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java deleted file mode 100644 index 3465fba2a10..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/user/UserSessionFilterTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.server.user; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.sonar.core.platform.ComponentContainer; -import org.sonar.db.DBSessions; -import org.sonar.server.authentication.UserSessionInitializer; -import org.sonar.server.organization.DefaultOrganizationCache; -import org.sonar.server.platform.Platform; -import org.sonar.server.setting.ThreadLocalSettings; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class UserSessionFilterTest { - - private UserSessionInitializer userSessionInitializer = mock(UserSessionInitializer.class); - private ComponentContainer container = new ComponentContainer(); - private Platform platform = mock(Platform.class); - private HttpServletRequest request = mock(HttpServletRequest.class); - private HttpServletResponse response = mock(HttpServletResponse.class); - private FilterChain chain = mock(FilterChain.class); - private DBSessions dbSessions = mock(DBSessions.class); - private ThreadLocalSettings settings = mock(ThreadLocalSettings.class); - private DefaultOrganizationCache defaultOrganizationCache = mock(DefaultOrganizationCache.class); - private UserSessionFilter underTest = new UserSessionFilter(platform); - - @Before - public void setUp() { - container.add(dbSessions, settings, defaultOrganizationCache); - when(platform.getContainer()).thenReturn(container); - } - - @Test - public void cleanup_user_session_after_request_handling() throws IOException, ServletException { - mockUserSessionInitializer(true); - - underTest.doFilter(request, response, chain); - - verify(chain).doFilter(request, response); - verify(userSessionInitializer).initUserSession(request, response); - } - - @Test - public void stop_when_user_session_return_false() throws Exception { - mockUserSessionInitializer(false); - - underTest.doFilter(request, response, chain); - - verify(chain, never()).doFilter(request, response); - verify(userSessionInitializer).initUserSession(request, response); - } - - @Test - public void does_nothing_when_not_initialized() throws Exception { - underTest.doFilter(request, response, chain); - - verify(chain).doFilter(request, response); - verifyZeroInteractions(userSessionInitializer); - } - - @Test - public void doFilter_loads_and_unloads_settings() throws Exception { - underTest.doFilter(request, response, chain); - - InOrder inOrder = inOrder(settings); - inOrder.verify(settings).load(); - inOrder.verify(settings).unload(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void doFilter_unloads_Settings_even_if_chain_throws_exception() throws Exception { - RuntimeException thrown = mockChainDoFilterError(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(settings).unload(); - } - } - - @Test - public void doFilter_enables_and_disables_caching_in_DbSessions() throws Exception { - underTest.doFilter(request, response, chain); - - InOrder inOrder = inOrder(dbSessions); - inOrder.verify(dbSessions).enableCaching(); - inOrder.verify(dbSessions).disableCaching(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void doFilter_disables_caching_in_DbSessions_even_if_chain_throws_exception() throws Exception { - RuntimeException thrown = mockChainDoFilterError(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(dbSessions).disableCaching(); - } - } - - @Test - public void doFilter_unloads_Settings_even_if_DefaultOrganizationCache_unload_fails() throws Exception { - RuntimeException thrown = new RuntimeException("Faking DefaultOrganizationCache.unload failing"); - doThrow(thrown) - .when(defaultOrganizationCache) - .unload(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(settings).unload(); - } - } - - @Test - public void doFilter_unloads_Settings_even_if_UserSessionInitializer_removeUserSession_fails() throws Exception { - RuntimeException thrown = mockUserSessionInitializerRemoveUserSessionFailing(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(settings).unload(); - } - } - - @Test - public void doFilter_loads_and_unloads_DefaultOrganizationCache() throws Exception { - underTest.doFilter(request, response, chain); - - InOrder inOrder = inOrder(defaultOrganizationCache); - inOrder.verify(defaultOrganizationCache).load(); - inOrder.verify(defaultOrganizationCache).unload(); - inOrder.verifyNoMoreInteractions(); - } - - @Test - public void doFilter_unloads_DefaultOrganizationCache_even_if_chain_throws_exception() throws Exception { - RuntimeException thrown = mockChainDoFilterError(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(defaultOrganizationCache).unload(); - } - } - - @Test - public void doFilter_unloads_DefaultOrganizationCache_even_if_Settings_unload_fails() throws Exception { - RuntimeException thrown = new RuntimeException("Faking Settings.unload failing"); - doThrow(thrown) - .when(settings) - .unload(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(defaultOrganizationCache).unload(); - } - } - - @Test - public void doFilter_unloads_DefaultOrganizationCache_even_if_UserSessionInitializer_removeUserSession_fails() throws Exception { - RuntimeException thrown = mockUserSessionInitializerRemoveUserSessionFailing(); - - try { - underTest.doFilter(request, response, chain); - fail("A RuntimeException should have been thrown"); - } catch (RuntimeException e) { - assertThat(e).isSameAs(thrown); - verify(defaultOrganizationCache).unload(); - } - } - - @Test - public void just_for_fun_and_coverage() throws ServletException { - UserSessionFilter filter = new UserSessionFilter(); - filter.init(mock(FilterConfig.class)); - filter.destroy(); - // do not fail - } - - private void mockUserSessionInitializer(boolean value) { - container.add(userSessionInitializer); - when(userSessionInitializer.initUserSession(request, response)).thenReturn(value); - } - - private RuntimeException mockUserSessionInitializerRemoveUserSessionFailing() { - container.add(userSessionInitializer); - RuntimeException thrown = new RuntimeException("Faking UserSessionInitializer.removeUserSession failing"); - doThrow(thrown) - .when(userSessionInitializer) - .removeUserSession(); - return thrown; - } - - private RuntimeException mockChainDoFilterError() throws IOException, ServletException { - RuntimeException thrown = new RuntimeException("Faking chain.doFilter failing"); - doThrow(thrown) - .when(chain) - .doFilter(request, response); - return thrown; - } -} diff --git a/server/sonar-server/src/test/resources/static/foo.txt b/server/sonar-server/src/test/resources/static/foo.txt deleted file mode 100644 index e69de29bb2d..00000000000 --- a/server/sonar-server/src/test/resources/static/foo.txt +++ /dev/null |