[#1372] Add SERVER_SERVLET_CONTEXT_PATH support (#1433)

added support for SERVER_SERVLET_CONTEXT_PATH. Could be used in some cases

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2023-09-26 11:58:38 +03:00
committed by GitHub
parent b51a5d6c90
commit e2d90b7092
5 changed files with 39 additions and 46 deletions

View File

@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties; import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties;
import org.eclipse.hawkbit.api.HostnameResolver; import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler; import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -58,8 +59,9 @@ public class PropertyHostnameResolverAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(ArtifactUrlHandler.class) @ConditionalOnMissingBean(ArtifactUrlHandler.class)
PropertyBasedArtifactUrlHandler propertyBasedArtifactUrlHandler( PropertyBasedArtifactUrlHandler propertyBasedArtifactUrlHandler(
final ArtifactUrlHandlerProperties urlHandlerProperties) { final ArtifactUrlHandlerProperties urlHandlerProperties,
return new PropertyBasedArtifactUrlHandler(urlHandlerProperties); @Value("${server.servlet.context-path:}") final String contextPath) {
return new PropertyBasedArtifactUrlHandler(urlHandlerProperties, contextPath);
} }
} }

View File

@@ -31,9 +31,12 @@ public class ArtifactUrlHandlerProperties {
*/ */
private final Map<String, UrlProtocol> protocols = new HashMap<>(); private final Map<String, UrlProtocol> protocols = new HashMap<>();
public Map<String, UrlProtocol> getProtocols() {
return protocols;
}
/** /**
* Protocol specific properties to generate URLs accordingly. * Protocol specific properties to generate URLs accordingly.
*
*/ */
public static class UrlProtocol { public static class UrlProtocol {
@@ -50,15 +53,10 @@ public class ArtifactUrlHandlerProperties {
private String rel = "download-http"; private String rel = "download-http";
/** /**
* Hypermedia ref pattern for this protocol. Supported place holders are * Hypermedia ref pattern for this protocol. Supported placeholders are the properties
* protocol,controllerId,targetId,targetIdBase62,ip,port,hostname, * supported by {@link PropertyBasedArtifactUrlHandler}.
* artifactFileName,artifactSHA1,
* artifactIdBase62,artifactId,tenant,softwareModuleId,
* softwareModuleIdBase62.
*
* The update server itself supports
*/ */
private String ref = "{protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}"; private String ref = PropertyBasedArtifactUrlHandler.DEFAULT_URL_PROTOCOL_REF;
/** /**
* Protocol name placeholder that can be used in ref pattern. * Protocol name placeholder that can be used in ref pattern.
@@ -150,11 +148,5 @@ public class ArtifactUrlHandlerProperties {
public void setProtocol(final String protocol) { public void setProtocol(final String protocol) {
this.protocol = protocol; this.protocol = protocol;
} }
} }
public Map<String, UrlProtocol> getProtocols() {
return protocols;
}
} }

View File

@@ -9,7 +9,6 @@
*/ */
package org.eclipse.hawkbit.api; package org.eclipse.hawkbit.api;
import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -23,8 +22,7 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.UrlProtocol; import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.UrlProtocol;
import org.slf4j.Logger; import org.springframework.util.ObjectUtils;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@@ -36,25 +34,24 @@ import org.springframework.util.StringUtils;
* well in the following {@link UrlProtocol#getRef()} patterns: * well in the following {@link UrlProtocol#getRef()} patterns:
* *
* Default: * Default:
* {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/ * {protocol}://{hostname}:{port}{contextPath}/{tenant}/controller/v1/{controllerId}/
* softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}
* *
* Default (MD5SUM files): * Default (MD5SUM files):
* {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/ * {protocol}://{hostname}:{port}{contextPath}/{tenant}/controller/v1/{controllerId}/
* softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}.MD5SUM * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}.MD5SUM
* *
*/ */
public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
private static final Logger LOG = LoggerFactory.getLogger(PropertyBasedArtifactUrlHandler.class);
private static final String PROTOCOL_PLACEHOLDER = "protocol"; private static final String PROTOCOL_PLACEHOLDER = "protocol";
private static final String HOSTNAME_PLACEHOLDER = "hostname";
private static final String IP_PLACEHOLDER = "ip";
private static final String PORT_PLACEHOLDER = "port";
private static final String CONTEXT_PATH = "contextPath";
private static final String CONTROLLER_ID_PLACEHOLDER = "controllerId"; private static final String CONTROLLER_ID_PLACEHOLDER = "controllerId";
private static final String TARGET_ID_BASE10_PLACEHOLDER = "targetId"; private static final String TARGET_ID_BASE10_PLACEHOLDER = "targetId";
private static final String TARGET_ID_BASE62_PLACEHOLDER = "targetIdBase62"; private static final String TARGET_ID_BASE62_PLACEHOLDER = "targetIdBase62";
private static final String IP_PLACEHOLDER = "ip";
private static final String PORT_PLACEHOLDER = "port";
private static final String HOSTNAME_PLACEHOLDER = "hostname";
private static final String HOSTNAME_REQUEST_PLACEHOLDER = "hostnameRequest"; private static final String HOSTNAME_REQUEST_PLACEHOLDER = "hostnameRequest";
private static final String PORT_REQUEST_PLACEHOLDER = "portRequest"; private static final String PORT_REQUEST_PLACEHOLDER = "portRequest";
private static final String HOSTNAME_WITH_DOMAIN_REQUEST_PLACEHOLDER = "domainRequest"; private static final String HOSTNAME_WITH_DOMAIN_REQUEST_PLACEHOLDER = "domainRequest";
@@ -68,14 +65,18 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
private static final String SOFTWARE_MODULE_ID_BASE10_PLACDEHOLDER = "softwareModuleId"; private static final String SOFTWARE_MODULE_ID_BASE10_PLACDEHOLDER = "softwareModuleId";
private static final String SOFTWARE_MODULE_ID_BASE62_PLACDEHOLDER = "softwareModuleIdBase62"; private static final String SOFTWARE_MODULE_ID_BASE62_PLACDEHOLDER = "softwareModuleIdBase62";
final static String DEFAULT_URL_PROTOCOL_REF = "{" + PROTOCOL_PLACEHOLDER + "}://{" + HOSTNAME_PLACEHOLDER + "}:{" + PORT_PLACEHOLDER + "}{" + CONTEXT_PATH + "}/{" + TENANT_PLACEHOLDER + "}/controller/v1/{" + CONTROLLER_ID_PLACEHOLDER + "}/softwaremodules/{" + SOFTWARE_MODULE_ID_BASE10_PLACDEHOLDER + "}/artifacts/{" + ARTIFACT_FILENAME_PLACEHOLDER + "}";
private final ArtifactUrlHandlerProperties urlHandlerProperties; private final ArtifactUrlHandlerProperties urlHandlerProperties;
private final String contextPath;
/** /**
* @param urlHandlerProperties * @param urlHandlerProperties
* for URL generation configuration * for URL generation configuration
*/ */
public PropertyBasedArtifactUrlHandler(final ArtifactUrlHandlerProperties urlHandlerProperties) { public PropertyBasedArtifactUrlHandler(final ArtifactUrlHandlerProperties urlHandlerProperties, final String contextPath) {
this.urlHandlerProperties = urlHandlerProperties; this.urlHandlerProperties = urlHandlerProperties;
this.contextPath = contextPath == null || "/".equals(contextPath) ? "" : contextPath; // normalize
} }
@Override @Override
@@ -85,7 +86,6 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
@Override @Override
public List<ArtifactUrl> getUrls(final URLPlaceholder placeholder, final ApiType api, final URI requestUri) { public List<ArtifactUrl> getUrls(final URLPlaceholder placeholder, final ApiType api, final URI requestUri) {
return urlHandlerProperties.getProtocols().values().stream() return urlHandlerProperties.getProtocols().values().stream()
.filter(urlProtocol -> urlProtocol.getSupports().contains(api) && urlProtocol.isEnabled()) .filter(urlProtocol -> urlProtocol.getSupports().contains(api) && urlProtocol.isEnabled())
.map(urlProtocol -> new ArtifactUrl(urlProtocol.getProtocol().toUpperCase(), urlProtocol.getRel(), .map(urlProtocol -> new ArtifactUrl(urlProtocol.getProtocol().toUpperCase(), urlProtocol.getRel(),
@@ -94,7 +94,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
} }
private static String generateUrl(final UrlProtocol protocol, final URLPlaceholder placeholder, private String generateUrl(final UrlProtocol protocol, final URLPlaceholder placeholder,
final URI requestUri) { final URI requestUri) {
final Set<Entry<String, String>> entrySet = getReplaceMap(protocol, placeholder, requestUri).entrySet(); final Set<Entry<String, String>> entrySet = getReplaceMap(protocol, placeholder, requestUri).entrySet();
@@ -103,17 +103,18 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
for (final Entry<String, String> entry : entrySet) { for (final Entry<String, String> entry : entrySet) {
if (entry.getKey().equals(PORT_PLACEHOLDER)) { if (entry.getKey().equals(PORT_PLACEHOLDER)) {
urlPattern = urlPattern.replace(":{" + entry.getKey() + "}", urlPattern = urlPattern.replace(":{" + entry.getKey() + "}",
StringUtils.isEmpty(entry.getValue()) ? "" : (":" + entry.getValue())); ObjectUtils.isEmpty(entry.getValue()) ? "" : (":" + entry.getValue()));
} else { } else {
if(entry.getValue() != null) { if(entry.getValue() != null) {
urlPattern = urlPattern.replace("{" + entry.getKey() + "}", entry.getValue()); urlPattern = urlPattern.replace("{" + entry.getKey() + "}", entry.getValue());
} }
} }
} }
return urlPattern; return urlPattern;
} }
private static Map<String, String> getReplaceMap(final UrlProtocol protocol, final URLPlaceholder placeholder, private Map<String, String> getReplaceMap(final UrlProtocol protocol, final URLPlaceholder placeholder,
final URI requestUri) { final URI requestUri) {
final Map<String, String> replaceMap = new HashMap<>(); final Map<String, String> replaceMap = new HashMap<>();
replaceMap.put(IP_PLACEHOLDER, protocol.getIp()); replaceMap.put(IP_PLACEHOLDER, protocol.getIp());
@@ -123,12 +124,10 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
replaceMap.put(PORT_REQUEST_PLACEHOLDER, getRequestPort(protocol, requestUri)); replaceMap.put(PORT_REQUEST_PLACEHOLDER, getRequestPort(protocol, requestUri));
replaceMap.put(HOSTNAME_WITH_DOMAIN_REQUEST_PLACEHOLDER, computeHostWithRequestDomain(protocol, requestUri)); replaceMap.put(HOSTNAME_WITH_DOMAIN_REQUEST_PLACEHOLDER, computeHostWithRequestDomain(protocol, requestUri));
try { replaceMap.put(CONTEXT_PATH, contextPath);
replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER,
URLEncoder.encode(placeholder.getSoftwareData().getFilename(), StandardCharsets.UTF_8.toString())); replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER,
} catch (final UnsupportedEncodingException e) { URLEncoder.encode(placeholder.getSoftwareData().getFilename(), StandardCharsets.UTF_8));
LOG.error("Could not encode {}", placeholder.getSoftwareData().getFilename(), e);
}
replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, placeholder.getSoftwareData().getSha1Hash()); replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, placeholder.getSoftwareData().getSha1Hash());
replaceMap.put(PROTOCOL_PLACEHOLDER, protocol.getProtocol()); replaceMap.put(PROTOCOL_PLACEHOLDER, protocol.getProtocol());
@@ -138,7 +137,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
replaceMap.put(TENANT_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTenantId())); replaceMap.put(TENANT_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTenantId()));
replaceMap.put(CONTROLLER_ID_PLACEHOLDER, placeholder.getControllerId()); replaceMap.put(CONTROLLER_ID_PLACEHOLDER, placeholder.getControllerId());
replaceMap.put(TARGET_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getTargetId())); replaceMap.put(TARGET_ID_BASE10_PLACEHOLDER, String.valueOf(placeholder.getTargetId()));
if(placeholder.getTargetId() != null) { if (placeholder.getTargetId() != null) {
replaceMap.put(TARGET_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTargetId())); replaceMap.put(TARGET_ID_BASE62_PLACEHOLDER, Base62Util.fromBase10(placeholder.getTargetId()));
} }
replaceMap.put(ARTIFACT_ID_BASE62_PLACEHOLDER, replaceMap.put(ARTIFACT_ID_BASE62_PLACEHOLDER,
@@ -168,7 +167,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
} }
private static String getPort(final UrlProtocol protocol) { private static String getPort(final UrlProtocol protocol) {
return protocol.getPort() == null ? null : String.valueOf(protocol.getPort()); return ObjectUtils.isEmpty(protocol.getPort()) ? null : String.valueOf(protocol.getPort());
} }
private static String computeHostWithRequestDomain(final UrlProtocol protocol, final URI requestUri) { private static String computeHostWithRequestDomain(final UrlProtocol protocol, final URI requestUri) {
@@ -188,7 +187,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler {
final String domain = StringUtils.collectionToDelimitedString(domainElements.subList(1, domainElements.size()), final String domain = StringUtils.collectionToDelimitedString(domainElements.subList(1, domainElements.size()),
"."); ".");
if (StringUtils.isEmpty(domain)) { if (ObjectUtils.isEmpty(domain)) {
return protocol.getHostname(); return protocol.getHostname();
} }

View File

@@ -62,7 +62,7 @@ public class PropertyBasedArtifactUrlHandlerTest {
@BeforeEach @BeforeEach
public void setup() { public void setup() {
properties = new ArtifactUrlHandlerProperties(); properties = new ArtifactUrlHandlerProperties();
urlHandlerUnderTest = new PropertyBasedArtifactUrlHandler(properties); urlHandlerUnderTest = new PropertyBasedArtifactUrlHandler(properties, "");
} }
@@ -88,7 +88,7 @@ public class PropertyBasedArtifactUrlHandlerTest {
proto.setPort(5683); proto.setPort(5683);
proto.setProtocol(TEST_PROTO); proto.setProtocol(TEST_PROTO);
proto.setRel(TEST_REL); proto.setRel(TEST_REL);
proto.setSupports(Arrays.asList(ApiType.DMF)); proto.setSupports(List.of(ApiType.DMF));
proto.setRef("{protocol}://{ip}:{port}/fw/{tenant}/{controllerId}/sha1/{artifactSHA1}"); proto.setRef("{protocol}://{ip}:{port}/fw/{tenant}/{controllerId}/sha1/{artifactSHA1}");
properties.getProtocols().put(TEST_PROTO, proto); properties.getProtocols().put(TEST_PROTO, proto);
@@ -109,7 +109,7 @@ public class PropertyBasedArtifactUrlHandlerTest {
proto.setPort(5683); proto.setPort(5683);
proto.setProtocol(TEST_PROTO); proto.setProtocol(TEST_PROTO);
proto.setRel(TEST_REL); proto.setRel(TEST_REL);
proto.setSupports(Arrays.asList(ApiType.DMF)); proto.setSupports(List.of(ApiType.DMF));
proto.setRef("{protocol}://{ip}:{port}/fws/{tenant}/{targetIdBase62}/{artifactIdBase62}"); proto.setRef("{protocol}://{ip}:{port}/fws/{tenant}/{targetIdBase62}/{artifactIdBase62}");
properties.getProtocols().put("ftp", proto); properties.getProtocols().put("ftp", proto);
@@ -132,7 +132,7 @@ public class PropertyBasedArtifactUrlHandlerTest {
proto.setPort(5683); proto.setPort(5683);
proto.setProtocol(TEST_PROTO); proto.setProtocol(TEST_PROTO);
proto.setRel(TEST_REL); proto.setRel(TEST_REL);
proto.setSupports(Arrays.asList(ApiType.DDI)); proto.setSupports(List.of(ApiType.DDI));
proto.setRef("{protocol}://{hostnameRequest}:{port}/fws/{tenant}/{targetIdBase62}/{artifactIdBase62}"); proto.setRef("{protocol}://{hostnameRequest}:{port}/fws/{tenant}/{targetIdBase62}/{artifactIdBase62}");
properties.getProtocols().put("ftp", proto); properties.getProtocols().put("ftp", proto);

View File

@@ -118,7 +118,7 @@ public class TestConfiguration implements AsyncConfigurer {
@Bean @Bean
PropertyBasedArtifactUrlHandler testPropertyBasedArtifactUrlHandler( PropertyBasedArtifactUrlHandler testPropertyBasedArtifactUrlHandler(
final ArtifactUrlHandlerProperties urlHandlerProperties) { final ArtifactUrlHandlerProperties urlHandlerProperties) {
return new PropertyBasedArtifactUrlHandler(urlHandlerProperties); return new PropertyBasedArtifactUrlHandler(urlHandlerProperties, "");
} }
@Bean @Bean