All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.conqat.engine.resource.util.UniformPathUtils Maven / Gradle / Ivy

/*
 * Copyright (c) CQSE GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.conqat.engine.resource.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.conqat.lib.commons.string.StringUtils;

/**
 * Utility methods for dealing with uniform paths.
 */
public class UniformPathUtils {

	/**
	 * Matches windows drive letters prefixes, e.g. "C:/", and captures the path
	 * after the drive letter as first group. Requires the path to be normalized
	 * before matching, as the pattern will not match '\'.
	 */
	public static final Pattern DRIVE_LETTER_PATTERN = Pattern.compile("[A-Za-z]:/(.*)");

	/** The character used as path separator in uniform paths. */
	public static final char SEPARATOR_CHAR = '/';

	/** String representation of {@link #SEPARATOR_CHAR}. */
	public static final String SEPARATOR = String.valueOf(SEPARATOR_CHAR);

	/** Pattern used for splitting along the separator. */
	private static final Pattern SPLIT_PATTERN = Pattern.compile("(?= 0) {
			return uniformPath.substring(pos + 1);
		}
		return uniformPath;
	}

	/**
	 * Returns the element name for a uniform path, which is everything starting
	 * from the last {@link #SEPARATOR_CHAR}.
	 */
	public static String getElementName(String uniformPath) {
		return StringUtils.getLastPart(uniformPath, SEPARATOR_CHAR);
	}

	/**
	 * Returns the parent path for a path which is everything up to the last
	 * non-escaped {@link #SEPARATOR_CHAR}. If no separator is found, the empty
	 * string is returned.
	 */
	public static String getParentPath(String uniformPath) {
		// we can not use StringUtils.removeLastPart(), as the behavior for a
		// string without separator is different here
		Matcher matcher = SPLIT_PATTERN.matcher(uniformPath);
		int idx = -1;
		while (matcher.find()) {
			idx = matcher.start();
		}
		if (idx == -1) {
			return StringUtils.EMPTY_STRING;
		}
		return uniformPath.substring(0, idx);
	}

	/** Removes the first count segments from the given path. */
	public static String removeFirstSegments(String uniformPath, int count) {
		String[] segments = splitPath(uniformPath);
		return concatenate(Arrays.copyOfRange(segments, count, segments.length));
	}

	/** Removes the last count segments from the given path. */
	public static String removeLastSegments(String uniformPath, int count) {
		String[] segments = splitPath(uniformPath);
		return concatenate(Arrays.copyOfRange(segments, 0, segments.length - count));
	}

	/** Returns segments forming the given path. */
	public static String[] splitPath(String uniformPath) {
		return SPLIT_PATTERN.split(uniformPath);
	}

	/**
	 * Returns the extension of the uniform path.
	 * 
	 * @return File extension, i.e. "java" for "FileSystemUtils.java", or
	 *         null, if the path has no extension (i.e. if a path
	 *         contains no '.'), returns the empty string if the '.' is the path's
	 *         last character.
	 */
	public static String getExtension(String uniformPath) {
		String name = getElementName(uniformPath);
		int posLastDot = name.lastIndexOf('.');
		if (posLastDot < 0) {
			return null;
		}
		return name.substring(posLastDot + 1);
	}

	/**
	 * Replaces forward and backward slashes, not only system-specific separators,
	 * with a forward slash. We do this on purpose, since paths that e.g. are read
	 * from files do not necessarily contain the separators contained in
	 * File.separator.
	 */
	public static String normalizeAllSeparators(String path) {
		return path.replaceAll("[/\\\\]+", "/");
	}

	/**
	 * Creates a clean path by resolving duplicate slashes, single and double dots.
	 * This is the equivalent to path canonization on uniform paths.
	 */
	public static String cleanPath(String path) {
		String[] parts = splitPath(path);
		for (int i = 0; i < parts.length; ++i) {
			// do not use StringUtils.isEmpty(), as we do not want trim
			// semantics!
			if (StringUtils.EMPTY_STRING.equals(parts[i]) || ".".equals(parts[i])) {
				parts[i] = null;
			} else if ("..".equals(parts[i])) {
				// cancel last non-null (if any)
				int j = i - 1;
				for (; j >= 0; --j) {
					if ("..".equals(parts[j])) {
						// another '..' acts as boundary
						break;
					}
					if (parts[j] != null) {
						// cancel both parts of the path.
						parts[j] = null;
						parts[i] = null;
						break;
					}
				}
			}
		}

		return joinPath(parts);
	}

	/** Joins the given array as a path, but ignoring null entries. */
	private static String joinPath(String[] parts) {
		StringBuilder sb = new StringBuilder();
		for (String part : parts) {
			if (part != null) {
				if (sb.length() > 0) {
					sb.append(SEPARATOR_CHAR);
				}
				sb.append(part);
			}
		}

		return sb.toString();
	}

	/**
	 * For a uniform path denoting a file and a relative path, constructs the
	 * uniform path for the relatively addressed element.
	 */
	public static String resolveRelativePath(String basePath, String relative) {
		// obtain "directory" from path denoting file
		String directory = getParentPath(basePath);
		if (!directory.isEmpty()) {
			directory += SEPARATOR;
		}
		return cleanPath(directory + relative);
	}

	/**
	 * Returns the concatenated path of all given parts. Empty or null strings are
	 * ignored.
	 */
	public static String concatenate(String... parts) {
		List list = new ArrayList<>(parts.length);
		for (String part : parts) {
			if (!StringUtils.isEmpty(part)) {
				list.add(part);
			}
		}
		return StringUtils.concat(list, SEPARATOR);
	}

	/**
	 * Remove drive letters or unix root slash from path. Also normalizes the path.
	 */
	public static String createSystemIndependentPath(String path) {
		Matcher m1 = DRIVE_LETTER_PATTERN.matcher(normalizeAllSeparators(path));
		if (m1.matches()) {
			// Remove drive letter
			path = m1.group(1);
		}

		// Remove unix root slash
		path = StringUtils.stripPrefix(path, "/");
		return path;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy