
com.sdl.dxa.common.util.PathUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dxa-common Show documentation
Show all versions of dxa-common Show documentation
DXA Common project contains framework common classes shared between all other artifacts
package com.sdl.dxa.common.util;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.URIBuilder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URISyntaxException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.springframework.util.StringUtils.isEmpty;
/**
* This utils class holds helper-methods for the logic related to operations with page paths.
*
*/
@Slf4j
public final class PathUtils {
private static final String DEFAULT_PAGE_NAME = "index";
private static final String DEFAULT_PAGE_EXTENSION = ".html";
private static final Pattern PAGE_TITLE_SEQUENCE = Pattern.compile("^(?\\d{3}\\s?)(?(?[^\\d]).*)$");
private static final Pattern FILE_NAME_PATTERN = Pattern.compile(".*?/?(?[^/.]*)(\\.(?[^/.]*))?$");
private static final Pattern INDEX_PATH_REGEXP = Pattern.compile("^(?.*)(?/(index(\\.html)?)?)$", Pattern.CASE_INSENSITIVE);
private PathUtils() {
}
public static String getDefaultPageName() {
return DEFAULT_PAGE_NAME;
}
public static String getDefaultPageExtension() {
return DEFAULT_PAGE_EXTENSION;
}
/**
* Replaces multiple slashes from the path.
*
* <empty> -> /
* / -> /
* // -> /
* /articles/ + legacy -> /articles/legacy
* /articles + /legacy -> /articles/legacy
* /articles/ + /legacy -> /articles/legacy
*
*
* @param path path to normalize
* @return a normalized path
*/
@Contract("null,null -> null; !null,_ -> !null; _,!null -> !null")
public static String combinePath(String url, String path) {
String securedUrl, securedPath;
if (url == null && path == null) {
return null;
}
securedUrl = url == null ? "" : url;
securedPath = path == null ? "" : path;
return securedUrl.concat("/").concat(securedPath).replaceAll("/+", "/");
}
/**
* Normalizes given path to have an explicit page name and extension.
* Adds an explicit index
page name if other page is not in a path
.
* Adds an explicit .html
extension if other extension is not in a path
.
*
* <empty> -> index.html
* / -> /index.html
* test -> test.html
* /test/ -> /test/index.html
* page.ext -> page.ext
*
*
* @param path path to normalize
* @return a normalized path
*/
public static String normalizePathToDefaults(String path) {
return normalizePathToDefaults(path, false);
}
public static String normalizePathToDefaults(String path, boolean tryIndexPage) {
log.trace("normalizePathToDefaults({})", path);
String processingPath = path;
if (isEmpty(processingPath)) {
return DEFAULT_PAGE_NAME + DEFAULT_PAGE_EXTENSION;
}
if (processingPath.endsWith("/")) {
processingPath = processingPath + DEFAULT_PAGE_NAME + DEFAULT_PAGE_EXTENSION;
}
if (!hasExtension(processingPath)) {
processingPath = tryIndexPage
? processingPath + "/" + DEFAULT_PAGE_NAME + DEFAULT_PAGE_EXTENSION
: processingPath + DEFAULT_PAGE_EXTENSION;
}
log.trace("return {}", processingPath);
return processingPath;
}
/**
* Checks if the given path has an extension.
*
* @param path path to check
* @return whether the path has any extension
*/
public static boolean hasExtension(@NotNull String path) {
return path.lastIndexOf('.') > path.lastIndexOf('/');
}
/**
* Checks whether the given path ends with a default extension.
* Keep in mind that page without name is impossible, so passing '.html' would give {@code false}.
*
* @param path the path to check
* @return whether the path ends with the default extension '.html'
*/
public static boolean hasDefaultExtension(@Nullable String path) {
return path != null && path.endsWith(DEFAULT_PAGE_EXTENSION) && path.length() > DEFAULT_PAGE_EXTENSION.length();
}
/**
* Strips the default page extension from the page path.
*
* @param path path to process
* @return path without a default extension
*/
@Contract("null -> null; !null -> !null")
@Nullable
public static String stripDefaultExtension(@Nullable String path) {
if (path == null) {
return null;
}
if (path.endsWith(DEFAULT_PAGE_EXTENSION)) {
log.trace("Stripping default extension {} from path {}", DEFAULT_PAGE_EXTENSION, path);
return path.substring(0, path.lastIndexOf(DEFAULT_PAGE_EXTENSION));
}
return path;
}
/**
* Removes sequence digits from the page title. Sequence number is always 3-digit.
* If no sequence number is found, then the string is not changed.
*
* 001 Home
will be "Home"
* Home
will stay "Home"
*
*
* @param pageTitle page title which may contain a sequence number
* @return string without sequence number, null parameter returns null
*/
@Contract("null -> null; !null -> !null")
public static String removeSequenceFromPageTitle(String pageTitle) {
if (pageTitle == null) {
return null;
}
Matcher matcher = PAGE_TITLE_SEQUENCE.matcher(pageTitle);
return matcher.matches() ? matcher.group("pageName").replaceFirst("^\\s", "") : pageTitle;
}
/**
* Returns whether the given page title contains sequence numbers.
*
* @param pageTitle page title to check
* @return true if the page contains sequence number, false otherwise
*/
public static boolean isWithSequenceDigits(String pageTitle) {
if (pageTitle == null) {
return false;
}
Matcher matcher = PAGE_TITLE_SEQUENCE.matcher(pageTitle);
return matcher.matches() && matcher.group("sequence") != null;
}
/**
* Checks if the given path is an index
path. Basically checks if the path ends with either 'index' or 'index.html'.
* Paths thath are finished with "/" and not with "index" are NOT index pages. Although they technically are.
*
* /page/index => true
* /page/index.html => true
*
*
* @param urlToCheck url to check
* @return true if index path, false otherwise
*/
public static boolean isIndexPath(@Nullable String urlToCheck) {
return urlToCheck != null && INDEX_PATH_REGEXP.matcher(urlToCheck.replaceFirst("/$", "")).matches();
}
/**
* Decides if the current request path is in a given context path. In other words decides whether requested {@code path}
* is in a context of current {@code request}.
*
* request to {@code /page} is in context of path {@code /page}
* request to {@code /page/child} is in context of path {@code /page} and {@code /page/child}
* but definitely not in {@code /other} nor {@code /other/child}
*
* There is a special treatment of {@code /} home requests. Home request is only in same context if path is
* exactly {@code /}
because any request then is in context of home.
*
* @param requestPath current request path
* @param localizationPath current localization path
* @param path given path to test against
* @return whether we can say that request is under context of path
*/
public static boolean isActiveContextPath(@Nullable String requestPath, @Nullable String localizationPath, @Nullable String path) {
String stripIndexPath = stripIndexPath(path);
String originatingRequestUri = stripIndexPath(requestPath);
if (stripIndexPath == null || originatingRequestUri == null) {
log.trace("Path or originating path is null, return false");
return false;
}
if (isHomePath(originatingRequestUri, localizationPath) || isHomePath(stripIndexPath, localizationPath)) {
return stripIndexPath.equalsIgnoreCase(originatingRequestUri);
}
return originatingRequestUri.startsWith(stripIndexPath);
}
/**
* Strips the index path from the page path.
*
* @param path path to process
* @return path without 'index' part if any
*/
@Nullable
public static String stripIndexPath(@Nullable String path) {
if (path == null) {
return null;
}
Matcher matcher = INDEX_PATH_REGEXP.matcher(path);
return matcher.matches() ? defaultIfBlank(matcher.group("main"), "/") : path;
}
/**
* Tests whether the given path is home (or root) path of the given localization.
*
* @param urlToCheck url to test against
* @param homePath path to be considered as home path of the localization
* @return whether the URL provided is home (or root)
*/
public static boolean isHomePath(@Nullable String urlToCheck, @Nullable String homePath) {
return urlToCheck != null && defaultIfEmpty(homePath, "/").equalsIgnoreCase(urlToCheck);
}
/**
* Gets a file name without extension from full filename.
*
* @param fullFileName full file name with extension
* @return file name without extension, or null if doesn't match
*/
@Contract("null -> null")
public static String getFileName(@Nullable String fullFileName) {
return getFromFileName(fullFileName, "fileName");
}
/**
* Gets an extension without filename from full filename.
*
* @param fullFileName full file name with extension
* @return extension of the file, or null if doesn't match
*/
@Contract("null -> null")
public static String getExtension(@Nullable String fullFileName) {
return getFromFileName(fullFileName, "extension");
}
@Nullable
@Contract("null, _ -> null")
private static String getFromFileName(@Nullable String fullFileName, String groupName) {
if (fullFileName == null) {
return null;
}
Matcher matcher = FILE_NAME_PATTERN.matcher(fullFileName);
if (matcher.matches()) {
return matcher.group(groupName);
}
return null;
}
/**
* Replaces the path in a given URL with a given path.
*
* @param currentUrl url to change
* @param newPath path to replace the old path with
* @return full URL of current request with given path appended
*/
@Contract("_, _ -> !null")
@SneakyThrows(URISyntaxException.class)
public static String replaceContextPath(@NotNull String currentUrl, @NotNull String newPath) {
String pathToSet = new URIBuilder(newPath).getPath();
return new URIBuilder(currentUrl)
.setPath(pathToSet.startsWith("/") ? pathToSet : ("/" + pathToSet))
.build().toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy