tachyon.util.io.PathUtils.java Source code

Java tutorial

Introduction

Here is the source code for tachyon.util.io.PathUtils.java

Source

/*
 * Licensed to the University of California, Berkeley under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 tachyon.util.io;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FilenameUtils;

import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;

import tachyon.TachyonURI;
import tachyon.exception.InvalidPathException;

/**
 * Utilities related to both Tachyon paths like {@link tachyon.TachyonURI} and local file paths.
 */
public final class PathUtils {

    /**
     * Checks and normalizes the given path.
     *
     * @param path The path to clean up
     * @return a normalized version of the path, with single separators between path components and
     *         dot components resolved
     * @throws InvalidPathException if the path is invalid
     */
    public static String cleanPath(String path) throws InvalidPathException {
        validatePath(path);
        return FilenameUtils.separatorsToUnix(FilenameUtils.normalizeNoEndSeparator(path));
    }

    /**
     * Joins each element in paths in order, separated by {@code TachyonURI.SEPARATOR}.
     * <p>
     * For example,
     *
     * <pre>
     * {@code
     * concatPath("/myroot/", "dir", 1L, "filename").equals("/myroot/dir/1/filename");
     * concatPath("tachyon://myroot", "dir", "filename").equals("tachyon://myroot/dir/filename");
     * concatPath("myroot/", "/dir/", "filename").equals("myroot/dir/filename");
     * concatPath("/", "dir", "filename").equals("/dir/filename");
     * }
     * </pre>
     *
     * Note that empty element in base or paths is ignored.
     *
     * @param base base path
     * @param paths paths to concatenate
     * @return joined path
     * @throws IllegalArgumentException if base or paths is null
     */
    public static String concatPath(Object base, Object... paths) throws IllegalArgumentException {
        Preconditions.checkArgument(base != null, "Failed to concatPath: base is null");
        Preconditions.checkArgument(paths != null, "Failed to concatPath: a null set of paths");
        List<String> trimmedPathList = new ArrayList<String>();
        String trimmedBase = CharMatcher.is(TachyonURI.SEPARATOR.charAt(0))
                .trimTrailingFrom(base.toString().trim());
        trimmedPathList.add(trimmedBase);
        for (Object path : paths) {
            if (path == null) {
                continue;
            }
            String trimmedPath = CharMatcher.is(TachyonURI.SEPARATOR.charAt(0)).trimFrom(path.toString().trim());
            if (!trimmedPath.isEmpty()) {
                trimmedPathList.add(trimmedPath);
            }
        }
        if (trimmedPathList.size() == 1 && trimmedBase.isEmpty()) {
            // base must be "[/]+"
            return TachyonURI.SEPARATOR;
        }
        return Joiner.on(TachyonURI.SEPARATOR).join(trimmedPathList);

    }

    /**
     * Gets the parent of the file at a path.
     *
     * @param path The path
     * @return the parent path of the file; this is "/" if the given path is the root
     * @throws InvalidPathException if the path is invalid
     */
    public static String getParent(String path) throws InvalidPathException {
        String cleanedPath = cleanPath(path);
        String name = FilenameUtils.getName(cleanedPath);
        String parent = cleanedPath.substring(0, cleanedPath.length() - name.length() - 1);
        if (parent.isEmpty()) {
            // The parent is the root path
            return TachyonURI.SEPARATOR;
        }
        return parent;
    }

    /**
     * Gets the path components of the given path.
     *
     * @param path The path to split
     * @return the path split into components
     * @throws InvalidPathException if the path is invalid
     */
    public static String[] getPathComponents(String path) throws InvalidPathException {
        path = cleanPath(path);
        if (isRoot(path)) {
            String[] ret = new String[1];
            ret[0] = "";
            return ret;
        }
        return path.split(TachyonURI.SEPARATOR);
    }

    /**
     * Checks whether the given path contains the given prefix. The comparison happens at a component
     * granularity; for example, {@code hasPrefix(/dir/file, /dir)} should evaluate to true, while
     * {@code hasPrefix(/dir/file, /d)} should evaluate to false.
     *
     * @param path a path
     * @param prefix a prefix
     * @return whether the given path has the given prefix
     */
    public static boolean hasPrefix(String path, String prefix) throws InvalidPathException {
        String[] pathComponents = getPathComponents(path);
        String[] prefixComponents = getPathComponents(prefix);
        if (pathComponents.length < prefixComponents.length) {
            return false;
        }
        for (int i = 0; i < prefixComponents.length; i++) {
            if (!pathComponents[i].equals(prefixComponents[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * Checks if the given path is the root.
     *
     * @param path The path to check
     * @return true if the path is the root
     * @throws InvalidPathException if the path is invalid
     */
    public static boolean isRoot(String path) throws InvalidPathException {
        return TachyonURI.SEPARATOR.equals(cleanPath(path));
    }

    /**
     * Checks if the given path is properly formed.
     *
     * @param path The path to check
     * @throws InvalidPathException If the path is not properly formed
     */
    public static void validatePath(String path) throws InvalidPathException {
        if (path == null || path.isEmpty() || !path.startsWith(TachyonURI.SEPARATOR) || path.contains(" ")) {
            throw new InvalidPathException("Path " + path + " is invalid.");
        }
    }

    /**
     * Generates a deterministic temporary file name for the a path and a file id and a nonce.
     *
     * @param fileId a file id
     * @param nonce a nonce token
     * @param path a file path
     * @return a deterministic temporary file name
     */
    public static final String temporaryFileName(long fileId, long nonce, String path) {
        return path + ".tachyon." + fileId + "." + String.format("0x%16X", nonce) + ".tmp";
    }

    /**
     * Creates a unique path based off the caller.
     *
     * @return unique path based off the caller
     */
    public static final String uniqPath() {
        StackTraceElement caller = new Throwable().getStackTrace()[1];
        long time = System.nanoTime();
        return "/" + caller.getClassName() + "/" + caller.getMethodName() + "/" + time;
    }

    private PathUtils() {
    } // prevent instantiation
}