diff --git a/howtos/configuration.md b/howtos/configuration.md index 0ebb8dc..f58bc29 100644 --- a/howtos/configuration.md +++ b/howtos/configuration.md @@ -30,3 +30,5 @@ absorb: true | MultipleAnnotationPost | Is posting multiple annotations in one request possible. | true | | WapPort | The port under which the WAP service is reachable. This port is used for HTTP and HTTPS service. When 80 is set and a http service is used, the port is omitted. The same applies to HTTPS and port 443. This setting has influence on the root IRI and cannot be changed after a database has been created. For details refer to the Root Container section. | 80 | | RdfBackendImplementation | The qualifier of the used RDF backend implementation. The default backend is 'jena'. | jena | +| WapBaseUrl | An override for the base URL. Only use to run behind proxy or in a container. | | + diff --git a/howtos/root_container.md b/howtos/root_container.md index db18484..75effa0 100644 --- a/howtos/root_container.md +++ b/howtos/root_container.md @@ -29,6 +29,10 @@ Example 4: Hostname=host1.example.org, EnableHttps=true, WapPort=443 When using the installer (via --install or by starting the jar in an empty folder) it asks for this base configuration and shows its consequences on the root container IRI. +All of the above can be overwritten by using the `WapBaseUrl` property. +This property is intended to be used only in scenarios where the server is reachable from a different URL +and if this should or must be reflected in the database (reverse proxy, docker container). + If changing any of those parameters with an already running server is necessary, a deletion of the database is needed. It gets recreated on first startup after the configuration has been changed. @@ -38,6 +42,6 @@ It gets recreated on first startup after the configuration has been changed. Using manual database manipulation, a conversion of the database to fit the new root container IRI can be achieved, but this is not implemented in the application. The easiest way to achieve this would be to have the database been backed up to NQUADS (which retains the named graphs) and then run a simple text replacement of old IRI ==> new IRI. -This has never been tested and should be regarded as a good starting point at best. +Also see [data migration guide](https://github.com/kit-data-manager/wap-server/wiki/Migrating-a-Server-Instance-and-its-Data) for details. --- \ No newline at end of file diff --git a/src/main/java/edu/kit/scc/dem/wapsrv/app/ConfigurationKeys.java b/src/main/java/edu/kit/scc/dem/wapsrv/app/ConfigurationKeys.java index 224a37c..bcadab1 100644 --- a/src/main/java/edu/kit/scc/dem/wapsrv/app/ConfigurationKeys.java +++ b/src/main/java/edu/kit/scc/dem/wapsrv/app/ConfigurationKeys.java @@ -111,5 +111,13 @@ public enum ConfigurationKeys { /** * @see WapServerConfig#fallbackValidation */ - FallbackValidation + FallbackValidation, + /** + * @see WapServerConfig#contextPath + */ + ContextPath, + /** + * @see WapServerConfig#proxiedBasePath + */ + ProxiedBasePath } diff --git a/src/main/java/edu/kit/scc/dem/wapsrv/app/WapServerConfig.java b/src/main/java/edu/kit/scc/dem/wapsrv/app/WapServerConfig.java index 7d49cb9..9cc002a 100644 --- a/src/main/java/edu/kit/scc/dem/wapsrv/app/WapServerConfig.java +++ b/src/main/java/edu/kit/scc/dem/wapsrv/app/WapServerConfig.java @@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.util.PathMatcher; +import org.springframework.util.StringUtils; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; @@ -90,6 +91,8 @@ public class WapServerConfig extends WebMvcConfigurationSupport{ private static final String CORS_ALLOWED_ORIGINS_PATH_DEFAULT = "./cors_allowed_origins.conf"; private static final boolean FALLBACK_VALIDATION_DEFAULT = true; private static final String RDF_BACKEND_IMPLEMENTATION_DEFAULT = "jena"; + private static final String CONTEXT_PATH_DEFAULT = ""; + private static final String PROXYBASEPATH_DEFAULT = ""; /** * The single instance of the configuration @@ -245,6 +248,12 @@ public class WapServerConfig extends WebMvcConfigurationSupport{ @Value("${RdfBackendImplementation:" + RDF_BACKEND_IMPLEMENTATION_DEFAULT + "}") private String rdfBackendImplementation; + @Value("${server.servlet.context-path:" + CONTEXT_PATH_DEFAULT + "}") + private String contextPath = CONTEXT_PATH_DEFAULT; + + @Value("${WapBaseUrl:" + PROXYBASEPATH_DEFAULT + "}") + private String proxiedBasePath; + /** * The cors configuration to use */ @@ -362,6 +371,8 @@ public static Properties getDefaultProperties(){ props.put(ConfigurationKeys.SimpleFormatters.toString(), SIMPLE_FORMATTERS_DEFAULT); props.put(ConfigurationKeys.CorsAllowedOriginsPath.toString(), CORS_ALLOWED_ORIGINS_PATH_DEFAULT); props.put(ConfigurationKeys.FallbackValidation.toString(), FALLBACK_VALIDATION_DEFAULT + ""); + props.put(ConfigurationKeys.ContextPath.toString(), CONTEXT_PATH_DEFAULT); + props.put(ConfigurationKeys.ProxiedBasePath.toString(), PROXYBASEPATH_DEFAULT); if(ConfigurationKeys.values().length != props.size()){ throw new RuntimeException("Default properties and the ConfigurationKeys enum not in sync"); } @@ -715,6 +726,8 @@ public void updateConfig(Properties props){ corsAllowedOriginsPath = getProperty(props, ConfigurationKeys.CorsAllowedOriginsPath, CORS_ALLOWED_ORIGINS_PATH_DEFAULT); fallbackValidation = getProperty(props, ConfigurationKeys.FallbackValidation, FALLBACK_VALIDATION_DEFAULT); + contextPath = getProperty(props, ConfigurationKeys.ContextPath, CONTEXT_PATH_DEFAULT); + proxiedBasePath = getProperty(props, ConfigurationKeys.ProxiedBasePath, PROXYBASEPATH_DEFAULT); } private String getProperty(Properties newProps, ConfigurationKeys key, String defaultValue){ @@ -813,17 +826,18 @@ public boolean isRootWapUrl(String url){ * @return The base url */ public String getBaseUrl(){ + if(StringUtils.hasText(proxiedBasePath))return proxiedBasePath; if(enableHttps){ if(wapPort == 443){ - return "https://" + hostname; + return "https://" + hostname + contextPath; } else{ - return "https://" + hostname + ":" + wapPort; + return "https://" + hostname + ":" + wapPort + contextPath; } } else{ if(wapPort == 80){ - return "http://" + hostname; + return "http://" + hostname + contextPath; } else{ - return "http://" + hostname + ":" + wapPort; + return "http://" + hostname + ":" + wapPort + contextPath; } } } diff --git a/src/test/java/edu/kit/scc/dem/wapsrv/app/WapServerConfigTest.java b/src/test/java/edu/kit/scc/dem/wapsrv/app/WapServerConfigTest.java index b546e84..78f2c08 100644 --- a/src/test/java/edu/kit/scc/dem/wapsrv/app/WapServerConfigTest.java +++ b/src/test/java/edu/kit/scc/dem/wapsrv/app/WapServerConfigTest.java @@ -453,6 +453,24 @@ final void testGetBaseUrl() { assertNotNull(actual, "Could not get base url from WapServerConfig after setting wapPort == 443."); expected = "https://localhost"; assertEquals(expected, actual); + // test context path == context + paramProperties.setProperty(ConfigurationKeys.ContextPath.toString(), "/context"); + objWapServerConfig.updateConfig(paramProperties); + + actual = null; + actual = objWapServerConfig.getBaseUrl(); + assertNotNull(actual, "Could not get base url from WapServerConfig after setting context path."); + expected = "https://localhost/context"; + assertEquals(expected, actual); + // test WapBaseUrl = http://example.com + paramProperties.setProperty(ConfigurationKeys.ProxiedBasePath.toString(), "http://example.com"); + objWapServerConfig.updateConfig(paramProperties); + + actual = null; + actual = objWapServerConfig.getBaseUrl(); + assertNotNull(actual, "Could not get base url from WapServerConfig after setting WapBaseUrl."); + expected = "http://example.com"; + assertEquals(expected, actual); } /** diff --git a/webcontent/ExampleData.js b/webcontent/ExampleData.js index be45f37..5445c5b 100644 --- a/webcontent/ExampleData.js +++ b/webcontent/ExampleData.js @@ -50,7 +50,8 @@ class ExampleData { } if (window.location.origin !== "null") { - callback.settings["url"] = window.location.origin + "/webapp/" + "resources/examples/" + filename; + let contextpath = !window.location.pathname.startsWith("/webapp") ? window.location.pathname.split("/webapp").at(0) : "" + callback.settings["url"] = window.location.origin + contextpath + "/webapp/" + "resources/examples/" + filename; } else { return false; } diff --git a/webcontent/Main.js b/webcontent/Main.js index 338fa10..4f820a5 100644 --- a/webcontent/Main.js +++ b/webcontent/Main.js @@ -55,7 +55,8 @@ class Main { this.initEventHandler(); //init value for targetUrl if (window.location.origin !== "null") { - $("#targetUrl").val(window.location.origin + "/wap/"); + let contextpath = !window.location.pathname.startsWith("/webapp") ? window.location.pathname.split("/webapp").at(0) : "" + $("#targetUrl").val(window.location.origin + contextpath + "/wap/"); } }