contains the Web Server "executable", the Pico Container definition (to allow building it up from multiple modules) and Tomcat/JEE specific codetags/8.0
*/ | */ | ||||
package org.sonar.server.platform; | 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.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 | 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; | |||||
} | |||||
} | |||||
} | } |
public class RequestIdMDCStorage implements AutoCloseable { | public class RequestIdMDCStorage implements AutoCloseable { | ||||
public static final String HTTP_REQUEST_ID_MDC_KEY = "HTTP_REQUEST_ID"; | 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")); | MDC.put(HTTP_REQUEST_ID_MDC_KEY, requireNonNull(requestId, "Request ID can't be null")); | ||||
} | } | ||||
</filter> | </filter> | ||||
<filter> | <filter> | ||||
<filter-name>UserSessionFilter</filter-name> | <filter-name>UserSessionFilter</filter-name> | ||||
<filter-class>org.sonar.server.user.UserSessionFilter</filter-class> | |||||
<filter-class>org.sonar.server.platform.web.UserSessionFilter</filter-class> | |||||
</filter> | </filter> | ||||
<filter> | <filter> | ||||
<filter-name>SetCharacterEncodingFilter</filter-name> | <filter-name>SetCharacterEncodingFilter</filter-name> | ||||
</filter> | </filter> | ||||
<filter> | <filter> | ||||
<filter-name>RequestUidFilter</filter-name> | <filter-name>RequestUidFilter</filter-name> | ||||
<filter-class>org.sonar.server.platform.web.requestid.RequestIdFilter</filter-class> | |||||
<filter-class>org.sonar.server.platform.web.RequestIdFilter</filter-class> | |||||
</filter> | </filter> | ||||
<filter> | <filter> | ||||
<filter-name>WebPagesFilter</filter-name> | <filter-name>WebPagesFilter</filter-name> | ||||
<servlet> | <servlet> | ||||
<servlet-name>static</servlet-name> | <servlet-name>static</servlet-name> | ||||
<servlet-class>org.sonar.server.plugins.StaticResourcesServlet</servlet-class> | |||||
<servlet-class>org.sonar.server.platform.web.StaticResourcesServlet</servlet-class> | |||||
</servlet> | </servlet> | ||||
<servlet-mapping> | <servlet-mapping> |
description = 'SonarQube WebServer' | |||||
sonarqube { | |||||
properties { | |||||
property 'sonar.projectName', "${projectTitle} :: WebServer" | |||||
} | |||||
} | |||||
dependencies { | |||||
// please keep the list grouped by configuration and ordered by name | |||||
compile 'com.google.guava:guava' | |||||
compile 'org.apache.tomcat.embed:tomcat-embed-core' | |||||
compile project(':sonar-core') | |||||
compile project(':server:sonar-process') | |||||
compile project(':server:sonar-server') | |||||
compile project(':server:sonar-server-common') | |||||
compileOnly 'com.google.code.findbugs:jsr305' | |||||
testCompile 'com.google.code.findbugs:jsr305' | |||||
testCompile 'org.eclipse.jetty:jetty-server' | |||||
testCompile 'org.eclipse.jetty:jetty-servlet' | |||||
testCompile 'org.mockito:mockito-core' | |||||
testCompile project(':sonar-testing-harness') | |||||
} |
/* | |||||
* 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; | |||||
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 PlatformImpl implements Platform { | |||||
private static final Logger LOGGER = Loggers.get(Platform.class); | |||||
private static final PlatformImpl INSTANCE = new PlatformImpl(); | |||||
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(PlatformImpl.class)); | |||||
private PlatformImpl() { | |||||
this.autoStarterSupplier = () -> { | |||||
ProcessCommandWrapper processCommandWrapper = getContainer().getComponentByType(ProcessCommandWrapper.class); | |||||
return new AsynchronousAutoStarter(processCommandWrapper); | |||||
}; | |||||
} | |||||
protected PlatformImpl(Supplier<AutoStarter> autoStarterSupplier) { | |||||
this.autoStarterSupplier = autoStarterSupplier; | |||||
} | |||||
public static PlatformImpl 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" | |||||
@Override | |||||
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(PlatformImpl.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(PlatformImpl.this::stopSafeModeContainer); | |||||
} | |||||
}); | |||||
} | |||||
} | |||||
private boolean dbRequiresMigration() { | |||||
return getDatabaseStatus() != DatabaseVersion.Status.UP_TO_DATE; | |||||
} | |||||
public boolean isStarted() { | |||||
return status() == Status.UP; | |||||
} | |||||
public boolean isInSafeMode() { | |||||
return status() == Status.SAFEMODE; | |||||
} | |||||
@Override | |||||
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)); | |||||
} | |||||
/** | |||||
* 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); | |||||
} | |||||
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); | |||||
} | |||||
@Override | |||||
public ComponentContainer getContainer() { | |||||
return currentLevel.getContainer(); | |||||
} | |||||
public Object getComponent(Object key) { | |||||
return getContainer().getComponentByKey(key); | |||||
} | |||||
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; | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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; | |||||
import javax.annotation.ParametersAreNonnullByDefault; |
import org.sonar.server.platform.SettingsChangeNotifier; | import org.sonar.server.platform.SettingsChangeNotifier; | ||||
import org.sonar.server.platform.WebCoreExtensionsInstaller; | import org.sonar.server.platform.WebCoreExtensionsInstaller; | ||||
import org.sonar.server.platform.monitoring.WebSystemInfoModule; | 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.web.requestid.HttpRequestIdModule; | ||||
import org.sonar.server.platform.ws.ChangeLogLevelActionModule; | import org.sonar.server.platform.ws.ChangeLogLevelActionModule; | ||||
import org.sonar.server.platform.ws.DbMigrationStatusAction; | import org.sonar.server.platform.ws.DbMigrationStatusAction; | ||||
ServerWs.class, | ServerWs.class, | ||||
BackendCleanup.class, | BackendCleanup.class, | ||||
IndexDefinitions.class, | IndexDefinitions.class, | ||||
WebPagesFilter.class, | |||||
WebAnalyticsLoaderImpl.class, | WebAnalyticsLoaderImpl.class, | ||||
// batch | // batch |
*/ | */ | ||||
package org.sonar.server.platform.platformlevel; | package org.sonar.server.platform.platformlevel; | ||||
import org.sonar.server.platform.ws.SafeModeHealthActionModule; | |||||
import org.sonar.server.authentication.SafeModeUserSession; | import org.sonar.server.authentication.SafeModeUserSession; | ||||
import org.sonar.server.organization.NoopDefaultOrganizationCache; | import org.sonar.server.organization.NoopDefaultOrganizationCache; | ||||
import org.sonar.server.platform.ServerImpl; | import org.sonar.server.platform.ServerImpl; | ||||
import org.sonar.server.platform.db.migration.DatabaseMigrationImpl; | import org.sonar.server.platform.db.migration.DatabaseMigrationImpl; | ||||
import org.sonar.server.platform.db.migration.MigrationEngineModule; | import org.sonar.server.platform.db.migration.MigrationEngineModule; | ||||
import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl; | 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.DbMigrationStatusAction; | ||||
import org.sonar.server.platform.ws.IndexAction; | import org.sonar.server.platform.ws.IndexAction; | ||||
import org.sonar.server.platform.ws.L10nWs; | import org.sonar.server.platform.ws.L10nWs; | ||||
import org.sonar.server.platform.ws.MigrateDbAction; | import org.sonar.server.platform.ws.MigrateDbAction; | ||||
import org.sonar.server.platform.ws.SafeModeHealthActionModule; | |||||
import org.sonar.server.platform.ws.StatusAction; | import org.sonar.server.platform.ws.StatusAction; | ||||
import org.sonar.server.platform.ws.SystemWs; | import org.sonar.server.platform.ws.SystemWs; | ||||
import org.sonar.server.ws.WebServiceEngine; | import org.sonar.server.ws.WebServiceEngine; | ||||
protected void configureLevel() { | protected void configureLevel() { | ||||
add( | add( | ||||
ServerImpl.class, | ServerImpl.class, | ||||
WebPagesFilter.class, | |||||
// l10n WS | // l10n WS | ||||
L10nWs.class, | L10nWs.class, |
import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.web.ServletFilter; | import org.sonar.api.web.ServletFilter; | ||||
import org.sonar.server.platform.Platform; | |||||
import org.sonar.server.platform.PlatformImpl; | |||||
/** | /** | ||||
* Inspired by http://stackoverflow.com/a/7592883/229031 | * Inspired by http://stackoverflow.com/a/7592883/229031 | ||||
public void init(FilterConfig config) { | public void init(FilterConfig config) { | ||||
// Filters are already available in picocontainer unless a database migration is required. See | // Filters are already available in picocontainer unless a database migration is required. See | ||||
// org.sonar.server.startup.RegisterServletFilters. | // org.sonar.server.startup.RegisterServletFilters. | ||||
init(config, Platform.getInstance().getContainer().getComponentsByType(ServletFilter.class)); | |||||
init(config, PlatformImpl.getInstance().getContainer().getComponentsByType(ServletFilter.class)); | |||||
} | } | ||||
void init(FilterConfig config, List<ServletFilter> filters) { | void init(FilterConfig config, List<ServletFilter> filters) { |
import javax.servlet.ServletContextEvent; | import javax.servlet.ServletContextEvent; | ||||
import javax.servlet.ServletContextListener; | import javax.servlet.ServletContextListener; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.server.platform.Platform; | |||||
import org.sonar.server.platform.PlatformImpl; | |||||
public final class PlatformServletContextListener implements ServletContextListener { | public final class PlatformServletContextListener implements ServletContextListener { | ||||
static final String STARTED_ATTRIBUTE = "sonarqube.started"; | static final String STARTED_ATTRIBUTE = "sonarqube.started"; | ||||
String key = paramKeys.nextElement(); | String key = paramKeys.nextElement(); | ||||
props.put(key, servletContext.getInitParameter(key)); | props.put(key, servletContext.getInitParameter(key)); | ||||
} | } | ||||
Platform.getInstance().init(props, servletContext); | |||||
Platform.getInstance().doStart(); | |||||
PlatformImpl.getInstance().init(props, servletContext); | |||||
PlatformImpl.getInstance().doStart(); | |||||
event.getServletContext().setAttribute(STARTED_ATTRIBUTE, Boolean.TRUE); | event.getServletContext().setAttribute(STARTED_ATTRIBUTE, Boolean.TRUE); | ||||
} catch (org.sonar.api.utils.MessageException | org.sonar.process.MessageException e) { | } catch (org.sonar.api.utils.MessageException | org.sonar.process.MessageException e) { | ||||
Loggers.get(Platform.class).error("Web server startup failed: " + e.getMessage()); | |||||
Loggers.get(PlatformImpl.class).error("Web server startup failed: " + e.getMessage()); | |||||
stopQuietly(); | stopQuietly(); | ||||
} catch (Throwable t) { | } catch (Throwable t) { | ||||
Loggers.get(Platform.class).error("Web server startup failed", t); | |||||
Loggers.get(PlatformImpl.class).error("Web server startup failed", t); | |||||
stopQuietly(); | stopQuietly(); | ||||
throw new AbortTomcatStartException(); | throw new AbortTomcatStartException(); | ||||
} | } | ||||
private void stopQuietly() { | private void stopQuietly() { | ||||
try { | try { | ||||
Platform.getInstance().doStop(); | |||||
PlatformImpl.getInstance().doStop(); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
// ignored, but an error during startup generally prevents pico to be correctly stopped | // ignored, but an error during startup generally prevents pico to be correctly stopped | ||||
} | } | ||||
@Override | @Override | ||||
public void contextDestroyed(ServletContextEvent event) { | public void contextDestroyed(ServletContextEvent event) { | ||||
Platform.getInstance().doStop(); | |||||
PlatformImpl.getInstance().doStop(); | |||||
} | } | ||||
} | } |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.platform.web.requestid; | |||||
package org.sonar.server.platform.web; | |||||
import com.google.common.annotations.VisibleForTesting; | import com.google.common.annotations.VisibleForTesting; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import javax.servlet.ServletRequest; | import javax.servlet.ServletRequest; | ||||
import javax.servlet.ServletResponse; | import javax.servlet.ServletResponse; | ||||
import org.sonar.server.platform.Platform; | import org.sonar.server.platform.Platform; | ||||
import org.sonar.server.platform.PlatformImpl; | |||||
import org.sonar.server.platform.web.requestid.RequestIdGenerator; | |||||
import org.sonar.server.platform.web.requestid.RequestIdMDCStorage; | |||||
/** | /** | ||||
* A {@link Filter} that puts and removes the HTTP request ID from the {@link org.slf4j.MDC}. | * A {@link Filter} that puts and removes the HTTP request ID from the {@link org.slf4j.MDC}. | ||||
private final Platform platform; | private final Platform platform; | ||||
public RequestIdFilter() { | public RequestIdFilter() { | ||||
this(Platform.getInstance()); | |||||
this(PlatformImpl.getInstance()); | |||||
} | } | ||||
@VisibleForTesting | @VisibleForTesting |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.plugins; | |||||
package org.sonar.server.platform.web; | |||||
import com.google.common.annotations.VisibleForTesting; | import com.google.common.annotations.VisibleForTesting; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.core.platform.PluginRepository; | import org.sonar.core.platform.PluginRepository; | ||||
import org.sonar.core.extension.CoreExtensionRepository; | import org.sonar.core.extension.CoreExtensionRepository; | ||||
import org.sonar.server.platform.Platform; | |||||
import org.sonar.server.platform.PlatformImpl; | |||||
import org.sonarqube.ws.MediaTypes; | import org.sonarqube.ws.MediaTypes; | ||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
static class System { | static class System { | ||||
PluginRepository getPluginRepository() { | PluginRepository getPluginRepository() { | ||||
return Platform.getInstance().getContainer().getComponentByType(PluginRepository.class); | |||||
return PlatformImpl.getInstance().getContainer().getComponentByType(PluginRepository.class); | |||||
} | } | ||||
CoreExtensionRepository getCoreExtensionRepository() { | CoreExtensionRepository getCoreExtensionRepository() { | ||||
return Platform.getInstance().getContainer().getComponentByType(CoreExtensionRepository.class); | |||||
return PlatformImpl.getInstance().getContainer().getComponentByType(CoreExtensionRepository.class); | |||||
} | } | ||||
@CheckForNull | @CheckForNull |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.user; | |||||
package org.sonar.server.platform.web; | |||||
import com.google.common.annotations.VisibleForTesting; | import com.google.common.annotations.VisibleForTesting; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.sonar.server.authentication.UserSessionInitializer; | import org.sonar.server.authentication.UserSessionInitializer; | ||||
import org.sonar.server.organization.DefaultOrganizationCache; | import org.sonar.server.organization.DefaultOrganizationCache; | ||||
import org.sonar.server.platform.Platform; | import org.sonar.server.platform.Platform; | ||||
import org.sonar.server.platform.PlatformImpl; | |||||
import org.sonar.server.setting.ThreadLocalSettings; | import org.sonar.server.setting.ThreadLocalSettings; | ||||
public class UserSessionFilter implements Filter { | public class UserSessionFilter implements Filter { | ||||
private final Platform platform; | private final Platform platform; | ||||
public UserSessionFilter() { | public UserSessionFilter() { | ||||
this.platform = Platform.getInstance(); | |||||
this.platform = PlatformImpl.getInstance(); | |||||
} | } | ||||
@VisibleForTesting | @VisibleForTesting |
import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
import javax.servlet.http.HttpServletResponse; | import javax.servlet.http.HttpServletResponse; | ||||
import org.sonar.api.web.ServletFilter; | import org.sonar.api.web.ServletFilter; | ||||
import org.sonar.server.platform.Platform; | |||||
import org.sonar.server.platform.PlatformImpl; | |||||
import static java.nio.charset.StandardCharsets.UTF_8; | import static java.nio.charset.StandardCharsets.UTF_8; | ||||
import static java.util.Locale.ENGLISH; | import static java.util.Locale.ENGLISH; | ||||
private WebPagesCache webPagesCache; | private WebPagesCache webPagesCache; | ||||
public WebPagesFilter() { | public WebPagesFilter() { | ||||
this(Platform.getInstance().getContainer().getComponentByType(WebPagesCache.class)); | |||||
this(PlatformImpl.getInstance().getContainer().getComponentByType(WebPagesCache.class)); | |||||
} | } | ||||
@VisibleForTesting | @VisibleForTesting |
/* | |||||
* 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.web; | |||||
import javax.annotation.ParametersAreNonnullByDefault; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.startup; | |||||
package org.sonar.server.platform.web; | |||||
import javax.servlet.ServletException; | import javax.servlet.ServletException; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.sonar.api.web.ServletFilter; | 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.ArgumentMatchers.anyList; | ||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.platform.web.requestid; | |||||
package org.sonar.server.platform.web; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import javax.servlet.FilterChain; | import javax.servlet.FilterChain; | ||||
import org.slf4j.MDC; | import org.slf4j.MDC; | ||||
import org.sonar.core.platform.ComponentContainer; | import org.sonar.core.platform.ComponentContainer; | ||||
import org.sonar.server.platform.Platform; | import org.sonar.server.platform.Platform; | ||||
import org.sonar.server.platform.web.requestid.RequestIdGenerator; | |||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.assertj.core.api.Assertions.fail; | import static org.assertj.core.api.Assertions.fail; | ||||
private RequestIdFilter underTest = new RequestIdFilter(platform); | private RequestIdFilter underTest = new RequestIdFilter(platform); | ||||
@Before | @Before | ||||
public void setUp() throws Exception { | |||||
public void setUp() { | |||||
ComponentContainer container = new ComponentContainer(); | ComponentContainer container = new ComponentContainer(); | ||||
container.add(requestIdGenerator); | container.add(requestIdGenerator); | ||||
when(platform.getContainer()).thenReturn(container); | when(platform.getContainer()).thenReturn(container); |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.plugins; | |||||
package org.sonar.server.platform.web; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
package org.sonar.server.user; | |||||
package org.sonar.server.platform.web; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import javax.servlet.FilterChain; | import javax.servlet.FilterChain; |
private WebPagesCache underTest = new WebPagesCache(platform, mapSettings.asConfig(), officialDistribution); | private WebPagesCache underTest = new WebPagesCache(platform, mapSettings.asConfig(), officialDistribution); | ||||
@Before | @Before | ||||
public void setUp() throws Exception { | |||||
public void setUp() { | |||||
when(servletContext.getContextPath()).thenReturn(TEST_CONTEXT); | when(servletContext.getContextPath()).thenReturn(TEST_CONTEXT); | ||||
when(servletContext.getResourceAsStream("/index.html")).thenAnswer( | when(servletContext.getResourceAsStream("/index.html")).thenAnswer( | ||||
(Answer<InputStream>) invocationOnMock -> toInputStream("Content of default index.html with context [%WEB_CONTEXT%], status [%SERVER_STATUS%], instance [%INSTANCE%]", | (Answer<InputStream>) invocationOnMock -> toInputStream("Content of default index.html with context [%WEB_CONTEXT%], status [%SERVER_STATUS%], instance [%INSTANCE%]", |
<?xml version="1.0" encoding="UTF-8" ?> | |||||
<configuration debug="false"> | |||||
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/> | |||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> | |||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | |||||
<pattern> | |||||
%d{yyyy.MM.dd HH:mm:ss} %-5level %msg%n | |||||
</pattern> | |||||
</encoder> | |||||
</appender> | |||||
<root> | |||||
<level value="INFO"/> | |||||
<appender-ref ref="CONSOLE"/> | |||||
</root> | |||||
<logger name="ch.qos.logback"> | |||||
<level value="WARN"/> | |||||
</logger> | |||||
<logger name="okhttp3.mockwebserver"> | |||||
<level value="WARN"/> | |||||
</logger> | |||||
</configuration> |
include 'server:sonar-server-common' | include 'server:sonar-server-common' | ||||
include 'server:sonar-vsts' | include 'server:sonar-vsts' | ||||
include 'server:sonar-web' | include 'server:sonar-web' | ||||
include 'server:sonar-webserver' | |||||
include 'server:sonar-webserver-ws' | include 'server:sonar-webserver-ws' | ||||
include 'sonar-application' | include 'sonar-application' |
compile project(':server:sonar-ce') | compile project(':server:sonar-ce') | ||||
compile project(':server:sonar-main') | compile project(':server:sonar-main') | ||||
compile project(':server:sonar-process') | compile project(':server:sonar-process') | ||||
compile project(':server:sonar-server') | |||||
compile project(':server:sonar-webserver') | |||||
compile project(':sonar-core') | compile project(':sonar-core') | ||||
compile project(path: ':sonar-plugin-api', configuration: 'shadow') | compile project(path: ':sonar-plugin-api', configuration: 'shadow') | ||||
compile project(':sonar-plugin-api-impl') | compile project(':sonar-plugin-api-impl') |