From d6a835473c21084e3864da7f854e5000a4867843 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 30 Mar 2016 16:42:54 +0200 Subject: [PATCH] Revert "SONAR-7122 Drop the ability to customize the web app context" This reverts commit 8f7a9ad479a219fc22ac729a23f220e450c572b7. SONAR-7494 Reintroduce the web app context --- .../process/ProcessTest/sonar.properties | 4 ++ .../process/ProcessTest/sonar.properties | 4 ++ .../org/sonar/server/app/TomcatContexts.java | 17 ++++++-- .../org/sonar/server/platform/ServerImpl.java | 9 +++- .../sonar/server/app/TomcatContextsTest.java | 42 ++++++++++++++++--- .../sonar/server/platform/ServerImplTest.java | 14 +++++++ .../platform/ServerLifecycleNotifierTest.java | 2 +- .../app/views/layouts/_layout.html.erb | 2 +- .../app/views/measures/_copy_form.html.erb | 2 +- .../app/views/measures/_edit_form.html.erb | 2 +- .../app/views/measures/_favourites.html.erb | 2 +- .../app/views/measures/_save_as_form.html.erb | 2 +- .../WEB-INF/app/views/widget/index.html.erb | 2 +- .../src/main/assembly/conf/sonar.properties | 4 ++ .../java/org/sonar/api/platform/Server.java | 4 -- .../sonar/batch/platform/DefaultServer.java | 2 +- 16 files changed, 91 insertions(+), 23 deletions(-) diff --git a/server/sonar-process-monitor/src/test/resources/org/sonar/process/ProcessTest/sonar.properties b/server/sonar-process-monitor/src/test/resources/org/sonar/process/ProcessTest/sonar.properties index dd7a73de8ad..4c4ddb2f130 100644 --- a/server/sonar-process-monitor/src/test/resources/org/sonar/process/ProcessTest/sonar.properties +++ b/server/sonar-process-monitor/src/test/resources/org/sonar/process/ProcessTest/sonar.properties @@ -80,6 +80,10 @@ sonar.jdbc.timeBetweenEvictionRunsMillis=30000 # By default, ports will be used on all IP addresses associated with the server. #sonar.web.host=0.0.0.0 +# Web context. When set, it must start with forward slash (for example /sonarqube). +# The default value is root context (empty value). +#sonar.web.context= + # TCP port for incoming HTTP connections. Disabled when value is -1. #sonar.web.port=9000 diff --git a/server/sonar-process/src/test/resources/org/sonar/process/ProcessTest/sonar.properties b/server/sonar-process/src/test/resources/org/sonar/process/ProcessTest/sonar.properties index dd7a73de8ad..4c4ddb2f130 100644 --- a/server/sonar-process/src/test/resources/org/sonar/process/ProcessTest/sonar.properties +++ b/server/sonar-process/src/test/resources/org/sonar/process/ProcessTest/sonar.properties @@ -80,6 +80,10 @@ sonar.jdbc.timeBetweenEvictionRunsMillis=30000 # By default, ports will be used on all IP addresses associated with the server. #sonar.web.host=0.0.0.0 +# Web context. When set, it must start with forward slash (for example /sonarqube). +# The default value is root context (empty value). +#sonar.web.context= + # TCP port for incoming HTTP connections. Disabled when value is -1. #sonar.web.port=9000 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 index 7ed8a009486..abd0dd2df4e 100644 --- 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 @@ -28,6 +28,7 @@ import org.apache.catalina.Context; 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.api.utils.log.Loggers; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; @@ -46,7 +47,7 @@ public class TomcatContexts { private static final String JRUBY_MAX_RUNTIMES = "jruby.max.runtimes"; private static final String RAILS_ENV = "rails.env"; - private static final String ROOT_CONTEXT_PATH = ""; + public static final String PROPERTY_CONTEXT = "sonar.web.context"; public static final String WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR = "web/deploy"; private final Fs fs; @@ -61,9 +62,9 @@ public class TomcatContexts { } public StandardContext configure(Tomcat tomcat, Props props) { - addStaticDir(tomcat, "/deploy", new File(props.nonNullValueAsFile(ProcessProperties.PATH_DATA), WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR)); + addStaticDir(tomcat, getContextPath(props) + "/deploy", new File(props.nonNullValueAsFile(ProcessProperties.PATH_DATA), WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR)); - StandardContext webapp = addContext(tomcat, ROOT_CONTEXT_PATH, webappDir(props)); + StandardContext webapp = addContext(tomcat, getContextPath(props), webappDir(props)); configureRails(props, webapp); for (Map.Entry entry : props.rawProperties().entrySet()) { String key = entry.getKey().toString(); @@ -72,6 +73,16 @@ public class TomcatContexts { 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 { diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java index 3bb1156c454..49c15d20089 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java @@ -47,6 +47,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.sonar.api.CoreProperties.SERVER_BASE_URL; import static org.sonar.api.CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE; +import static org.sonar.server.app.TomcatContexts.PROPERTY_CONTEXT; public final class ServerImpl extends Server implements Startable { private static final String PROPERTY_SONAR_CORE_STARTED_AT = "sonar.core.startedAt"; @@ -62,6 +63,7 @@ public final class ServerImpl extends Server implements Startable { private String implementationBuild; private File sonarHome; private File deployDir; + private String contextPath; public ServerImpl(Settings settings) { this(settings, "/build.properties", "/sq-version.txt"); @@ -84,7 +86,6 @@ public final class ServerImpl extends Server implements Startable { version = readVersion(versionPath); implementationBuild = read(buildProperties).getProperty("Implementation-Build"); - sonarHome = new File(settings.getString(ProcessProperties.PATH_HOME)); if (!sonarHome.isDirectory()) { throw new IllegalStateException("SonarQube home directory is not valid"); @@ -92,6 +93,10 @@ public final class ServerImpl extends Server implements Startable { deployDir = new File(settings.getString(ProcessProperties.PATH_DATA), TomcatContexts.WEB_DEPLOY_PATH_RELATIVE_TO_DATA_DIR); + contextPath = StringUtils.defaultIfBlank(settings.getString(PROPERTY_CONTEXT), "") + // Remove trailing slashes + .replaceFirst("(\\/+)$", ""); + LOG.info("SonarQube {}", Joiner.on(" / ").skipNulls().join("Server", version, implementationBuild)); } catch (IOException e) { @@ -141,7 +146,7 @@ public final class ServerImpl extends Server implements Startable { @Override public String getContextPath() { - return ""; + return contextPath; } @Override 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 index e54244c4304..79f648f7608 100644 --- 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 @@ -31,6 +31,7 @@ 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.ProcessProperties; import org.sonar.process.Props; @@ -46,12 +47,13 @@ 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 { @@ -65,7 +67,7 @@ public class TomcatContextsTest { StandardContext context = mock(StandardContext.class); when(tomcat.addWebapp(anyString(), anyString())).thenReturn(context); - new TomcatContexts().configure(tomcat, new Props(props)); + underTest.configure(tomcat, new Props(props)); // configure webapp with properties verify(context).addParameter("foo", "bar"); @@ -76,7 +78,7 @@ public class TomcatContextsTest { props.setProperty("sonar.web.dev", "true"); Context context = mock(Context.class); - new TomcatContexts().configureRails(new Props(props), context); + underTest.configureRails(new Props(props), context); verify(context).addParameter("jruby.max.runtimes", "3"); verify(context).addParameter("rails.env", "development"); @@ -87,7 +89,7 @@ public class TomcatContextsTest { props.setProperty("sonar.web.dev", "false"); Context context = mock(Context.class); - new TomcatContexts().configureRails(new Props(props), context); + underTest.configureRails(new Props(props), context); verify(context).addParameter("jruby.max.runtimes", "1"); verify(context).addParameter("rails.env", "production"); @@ -98,7 +100,7 @@ public class TomcatContextsTest { File dir = temp.newFolder(); dir.delete(); - new TomcatContexts().addStaticDir(tomcat, "/deploy", dir); + underTest.addStaticDir(tomcat, "/deploy", dir); assertThat(dir).isDirectory().exists(); verify(tomcat).addWebapp("/deploy", dir.getAbsolutePath()); @@ -109,7 +111,7 @@ public class TomcatContextsTest { File dir = temp.newFolder(); FileUtils.touch(new File(dir, "foo.txt")); - new TomcatContexts().addStaticDir(tomcat, "/deploy", dir); + underTest.addStaticDir(tomcat, "/deploy", dir); assertThat(dir).isDirectory().exists(); assertThat(dir.listFiles()).isEmpty(); @@ -125,6 +127,34 @@ public class TomcatContextsTest { 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/ServerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java index 2ae0c0f1a21..44bf6aa07b2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java @@ -200,4 +200,18 @@ public class ServerImplTest { underTest.start(); assertThat(underTest.isSecured()).isFalse(); } + + @Test + public void get_context_path_from_settings() { + settings.setProperty("sonar.web.context", "/my_path"); + underTest.start(); + assertThat(underTest.getContextPath()).isEqualTo("/my_path"); + } + + @Test + public void sanitize_context_path_from_settings() { + settings.setProperty("sonar.web.context", "/my_path///"); + underTest.start(); + assertThat(underTest.getContextPath()).isEqualTo("/my_path"); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java index 275ef0edf42..d91368da8b4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java @@ -115,7 +115,7 @@ class FakeServer extends Server { @Override public String getContextPath() { - return ""; + return null; } @Override diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb index 956616e9c7b..1a2672d9fec 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb @@ -56,7 +56,7 @@ Documentation - Get Support - Plugins - - Web Service API + Web API diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_copy_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_copy_form.html.erb index 8112f5105a4..c18d3b3b4fd 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_copy_form.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_copy_form.html.erb @@ -17,4 +17,4 @@ $j("#copy-filter-form").modalForm({success: function (data) { window.location = window.baseUrl + '/measures/filter/' + data; }}); - + \ No newline at end of file diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb index 361edddcd9a..bbbd2da0a31 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_edit_form.html.erb @@ -17,4 +17,4 @@ $j("#edit-filter-form").modalForm({success: function (data) { window.location = window.baseUrl + '/measures/filter/' + data; }}); - + \ No newline at end of file diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_favourites.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_favourites.html.erb index 89618059614..77124eb9e98 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_favourites.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_favourites.html.erb @@ -9,4 +9,4 @@
  • <%= message('manage') %>
  • <% end %> - + \ No newline at end of file diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_save_as_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_save_as_form.html.erb index 2bfc2eb1516..00ecb3aa7a1 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_save_as_form.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/measures/_save_as_form.html.erb @@ -18,4 +18,4 @@ $j("#save-as-filter-form").modalForm({success:function (data) { window.location = window.baseUrl + '/measures/filter/' + data; }}); - + \ No newline at end of file diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/widget/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/widget/index.html.erb index ea9e4e3e9d5..3d718d0a954 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/widget/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/widget/index.html.erb @@ -41,4 +41,4 @@
    - + \ No newline at end of file diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties index 61d65a82b08..00f8bde74c6 100644 --- a/sonar-application/src/main/assembly/conf/sonar.properties +++ b/sonar-application/src/main/assembly/conf/sonar.properties @@ -100,6 +100,10 @@ # By default, ports will be used on all IP addresses associated with the server. #sonar.web.host=0.0.0.0 +# Web context. When set, it must start with forward slash (for example /sonarqube). +# The default value is root context (empty value). +#sonar.web.context= + # TCP port for incoming HTTP connections. Disabled when value is -1. #sonar.web.port=9000 diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java index 0968b5f3d03..62b5915e136 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java @@ -45,10 +45,6 @@ public abstract class Server { @CheckForNull public abstract File getDeployDir(); - /** - * @deprecated in 5.4. Web context path can not be configured. It's always {@code ""}. See https://jira.sonarsource.com/browse/SONAR-7122 - */ - @Deprecated public abstract String getContextPath(); /** diff --git a/sonar-scanner-engine/src/main/java/org/sonar/batch/platform/DefaultServer.java b/sonar-scanner-engine/src/main/java/org/sonar/batch/platform/DefaultServer.java index 3136f4a3112..b747438a9f5 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/batch/platform/DefaultServer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/batch/platform/DefaultServer.java @@ -80,7 +80,7 @@ public class DefaultServer extends Server { @Override public String getContextPath() { - return ""; + return null; } @Override -- 2.39.5