001/*- 002 * #%L 003 * Smile CDR - CDR 004 * %% 005 * Copyright (C) 2016 - 2026 Smile CDR, Inc. 006 * %% 007 * All rights reserved. 008 * #L% 009 */ 010package ca.cdr.test.util; 011 012import jakarta.annotation.Nonnull; 013import jakarta.annotation.Nullable; 014import org.apache.commons.lang3.StringUtils; 015 016/** 017 * Helpers for the URL paths under which Smile CDR modules are served. 018 */ 019// Created by Claude Opus 5.5 020public final class UrlPathUtil { 021 022 private UrlPathUtil() {} 023 024 /** 025 * Normalizes a module's {@code context_path} so that it can be appended to a 026 * {@code protocol://host:port} root as-is. 027 * 028 * @param theContextPath the configured context path; {@literal null}, blank and {@code /} all mean 029 * the root 030 * @return the empty string for the root, otherwise the path with one leading slash and no 031 * trailing slash, such as {@code /fhir-request} 032 */ 033 public static @Nonnull String normalizeContextPath(@Nullable String theContextPath) { 034 String trimmed = StringUtils.strip(StringUtils.trimToEmpty(theContextPath), "/"); 035 return trimmed.isEmpty() ? "" : "/" + trimmed; 036 } 037 038 /** 039 * Spring's {@code RestClient} appends a request's URI template to the base URL's path verbatim, 040 * so a base URL with a context path and no trailing slash turns {@code module-config/} into 041 * {@code /admin-jsonmodule-config/}. With the trailing slash, both {@code module-config/} and 042 * {@code /module-config/} resolve beneath the context path. 043 * 044 * @param theBaseUrl a base URL, with or without a trailing slash 045 * @return the same URL ending in exactly one slash 046 */ 047 public static @Nonnull String withTrailingSlash(@Nonnull String theBaseUrl) { 048 return theBaseUrl.endsWith("/") ? theBaseUrl : theBaseUrl + "/"; 049 } 050}