diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/PropertyHostnameResolverAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/PropertyHostnameResolverAutoConfiguration.java index 78cd46baa..1710d872a 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/PropertyHostnameResolverAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/PropertyHostnameResolverAutoConfiguration.java @@ -17,6 +17,7 @@ import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties; import org.eclipse.hawkbit.api.HostnameResolver; import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -58,8 +59,9 @@ public class PropertyHostnameResolverAutoConfiguration { @Bean @ConditionalOnMissingBean(ArtifactUrlHandler.class) PropertyBasedArtifactUrlHandler propertyBasedArtifactUrlHandler( - final ArtifactUrlHandlerProperties urlHandlerProperties) { - return new PropertyBasedArtifactUrlHandler(urlHandlerProperties); + final ArtifactUrlHandlerProperties urlHandlerProperties, + @Value("${server.servlet.context-path:}") final String contextPath) { + return new PropertyBasedArtifactUrlHandler(urlHandlerProperties, contextPath); } } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java index d11226689..5a57e0970 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/ArtifactUrlHandlerProperties.java @@ -31,9 +31,12 @@ public class ArtifactUrlHandlerProperties { */ private final Map protocols = new HashMap<>(); + public Map getProtocols() { + return protocols; + } + /** * Protocol specific properties to generate URLs accordingly. - * */ public static class UrlProtocol { @@ -50,15 +53,10 @@ public class ArtifactUrlHandlerProperties { private String rel = "download-http"; /** - * Hypermedia ref pattern for this protocol. Supported place holders are - * protocol,controllerId,targetId,targetIdBase62,ip,port,hostname, - * artifactFileName,artifactSHA1, - * artifactIdBase62,artifactId,tenant,softwareModuleId, - * softwareModuleIdBase62. - * - * The update server itself supports + * Hypermedia ref pattern for this protocol. Supported placeholders are the properties + * supported by {@link PropertyBasedArtifactUrlHandler}. */ - 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. @@ -150,11 +148,5 @@ public class ArtifactUrlHandlerProperties { public void setProtocol(final String protocol) { this.protocol = protocol; } - } - - public Map getProtocols() { - return protocols; - } - } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java index 3030a01d1..e86fb9d20 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandler.java @@ -9,7 +9,6 @@ */ package org.eclipse.hawkbit.api; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -23,8 +22,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties.UrlProtocol; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -36,25 +34,24 @@ import org.springframework.util.StringUtils; * well in the following {@link UrlProtocol#getRef()} patterns: * * Default: - * {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/ + * {protocol}://{hostname}:{port}{contextPath}/{tenant}/controller/v1/{controllerId}/ * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName} * * Default (MD5SUM files): - * {protocol}://{hostname}:{port}/{tenant}/controller/v1/{controllerId}/ + * {protocol}://{hostname}:{port}{contextPath}/{tenant}/controller/v1/{controllerId}/ * softwaremodules/{softwareModuleId}/artifacts/{artifactFileName}.MD5SUM * */ 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 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 TARGET_ID_BASE10_PLACEHOLDER = "targetId"; 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 PORT_REQUEST_PLACEHOLDER = "portRequest"; 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_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 String contextPath; /** * @param urlHandlerProperties * for URL generation configuration */ - public PropertyBasedArtifactUrlHandler(final ArtifactUrlHandlerProperties urlHandlerProperties) { + public PropertyBasedArtifactUrlHandler(final ArtifactUrlHandlerProperties urlHandlerProperties, final String contextPath) { this.urlHandlerProperties = urlHandlerProperties; + this.contextPath = contextPath == null || "/".equals(contextPath) ? "" : contextPath; // normalize } @Override @@ -85,7 +86,6 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { @Override public List getUrls(final URLPlaceholder placeholder, final ApiType api, final URI requestUri) { - return urlHandlerProperties.getProtocols().values().stream() .filter(urlProtocol -> urlProtocol.getSupports().contains(api) && urlProtocol.isEnabled()) .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 Set> entrySet = getReplaceMap(protocol, placeholder, requestUri).entrySet(); @@ -103,17 +103,18 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { for (final Entry entry : entrySet) { if (entry.getKey().equals(PORT_PLACEHOLDER)) { urlPattern = urlPattern.replace(":{" + entry.getKey() + "}", - StringUtils.isEmpty(entry.getValue()) ? "" : (":" + entry.getValue())); + ObjectUtils.isEmpty(entry.getValue()) ? "" : (":" + entry.getValue())); } else { if(entry.getValue() != null) { urlPattern = urlPattern.replace("{" + entry.getKey() + "}", entry.getValue()); } } } + return urlPattern; } - private static Map getReplaceMap(final UrlProtocol protocol, final URLPlaceholder placeholder, + private Map getReplaceMap(final UrlProtocol protocol, final URLPlaceholder placeholder, final URI requestUri) { final Map replaceMap = new HashMap<>(); 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(HOSTNAME_WITH_DOMAIN_REQUEST_PLACEHOLDER, computeHostWithRequestDomain(protocol, requestUri)); - try { - replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, - URLEncoder.encode(placeholder.getSoftwareData().getFilename(), StandardCharsets.UTF_8.toString())); - } catch (final UnsupportedEncodingException e) { - LOG.error("Could not encode {}", placeholder.getSoftwareData().getFilename(), e); - } + replaceMap.put(CONTEXT_PATH, contextPath); + + replaceMap.put(ARTIFACT_FILENAME_PLACEHOLDER, + URLEncoder.encode(placeholder.getSoftwareData().getFilename(), StandardCharsets.UTF_8)); replaceMap.put(ARTIFACT_SHA1_PLACEHOLDER, placeholder.getSoftwareData().getSha1Hash()); 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(CONTROLLER_ID_PLACEHOLDER, placeholder.getControllerId()); 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(ARTIFACT_ID_BASE62_PLACEHOLDER, @@ -168,7 +167,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { } 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) { @@ -188,7 +187,7 @@ public class PropertyBasedArtifactUrlHandler implements ArtifactUrlHandler { final String domain = StringUtils.collectionToDelimitedString(domainElements.subList(1, domainElements.size()), "."); - if (StringUtils.isEmpty(domain)) { + if (ObjectUtils.isEmpty(domain)) { return protocol.getHostname(); } diff --git a/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java index b34f0c16f..771a5b78e 100644 --- a/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java +++ b/hawkbit-core/src/test/java/org/eclipse/hawkbit/api/PropertyBasedArtifactUrlHandlerTest.java @@ -62,7 +62,7 @@ public class PropertyBasedArtifactUrlHandlerTest { @BeforeEach public void setup() { properties = new ArtifactUrlHandlerProperties(); - urlHandlerUnderTest = new PropertyBasedArtifactUrlHandler(properties); + urlHandlerUnderTest = new PropertyBasedArtifactUrlHandler(properties, ""); } @@ -88,7 +88,7 @@ public class PropertyBasedArtifactUrlHandlerTest { proto.setPort(5683); proto.setProtocol(TEST_PROTO); 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}"); properties.getProtocols().put(TEST_PROTO, proto); @@ -109,7 +109,7 @@ public class PropertyBasedArtifactUrlHandlerTest { proto.setPort(5683); proto.setProtocol(TEST_PROTO); 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}"); properties.getProtocols().put("ftp", proto); @@ -132,7 +132,7 @@ public class PropertyBasedArtifactUrlHandlerTest { proto.setPort(5683); proto.setProtocol(TEST_PROTO); 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}"); properties.getProtocols().put("ftp", proto); diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java index 0792c5279..82d3dbdbe 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java @@ -118,7 +118,7 @@ public class TestConfiguration implements AsyncConfigurer { @Bean PropertyBasedArtifactUrlHandler testPropertyBasedArtifactUrlHandler( final ArtifactUrlHandlerProperties urlHandlerProperties) { - return new PropertyBasedArtifactUrlHandler(urlHandlerProperties); + return new PropertyBasedArtifactUrlHandler(urlHandlerProperties, ""); } @Bean