/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.vfs.server; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; /** * Path of VirtualFile. * * @author andrew00x */ public final class Path { /** Create new path. */ public static Path fromString(String path) { return new Path(parse(path)); } private static final String[] EMPTY_PATH = new String[0]; private static final Pattern PATH_SPLITTER = Pattern.compile("/"); private static String[] parse(String raw) { String[] parsed = ((raw == null) || raw.isEmpty() || ((raw.length() == 1) && (raw.charAt(0) == '/'))) ? EMPTY_PATH : PATH_SPLITTER.split(raw.charAt(0) == '/' ? raw.substring(1) : raw); if (parsed.length == 0) { return parsed; } List<String> newTokens = new ArrayList<>(parsed.length); for (String token : parsed) { if ("..".equals(token)) { int size = newTokens.size(); if (size == 0) { throw new IllegalArgumentException(String.format("Invalid path '%s', '..' on root. ", raw)); } newTokens.remove(size - 1); } else if (!".".equals(token)) { newTokens.add(token); } } return newTokens.toArray(new String[newTokens.size()]); } public static final Path ROOT = new Path(); private final String[] elements; private volatile int hashCode; private volatile String asString; private Path(String... elements) { this.elements = elements; } public Path getParent() { return isRoot() ? null : elements.length == 1 ? ROOT : subPath(0, elements.length - 1); } public Path subPath(int beginIndex) { return subPath(beginIndex, elements.length); } public Path subPath(int beginIndex, int endIndex) { if (beginIndex < 0 || beginIndex >= elements.length || endIndex > elements.length || beginIndex >= endIndex) { throw new IllegalArgumentException("Invalid end or begin index. "); } final int len = endIndex - beginIndex; final String[] subPath = new String[len]; System.arraycopy(elements, beginIndex, subPath, 0, len); return new Path(subPath); } public String getName() { return isRoot() ? "" : element(elements.length - 1); } public String[] elements() { String[] copy = new String[elements.length]; System.arraycopy(elements, 0, copy, 0, elements.length); return copy; } public int length() { return elements.length; } public String element(int index) { if (index < 0 || index >= elements.length) { throw new IllegalArgumentException("Invalid index. "); } return elements[index]; } public boolean isRoot() { return elements.length == 0; } public boolean isChild(Path parent) { if (parent.elements.length >= this.elements.length) { return false; } for (int i = 0, parentLength = parent.elements.length; i < parentLength; i++) { if (!parent.elements[i].equals(this.elements[i])) { return false; } } return true; } public Path newPath(String name) { final String[] relative = parse(name); if (relative.length == 0) { return this; // It is safety to return this instance since it is immutable. } final String[] absolute = new String[elements.length + relative.length]; System.arraycopy(elements, 0, absolute, 0, elements.length); System.arraycopy(relative, 0, absolute, elements.length, relative.length); return new Path(absolute); } public Path newPath(String... relative) { if (relative.length == 0) { return this; // It is safety to return this instance since it is immutable. } final String[] absolute = new String[elements.length + relative.length]; System.arraycopy(elements, 0, absolute, 0, elements.length); System.arraycopy(relative, 0, absolute, elements.length, relative.length); return new Path(absolute); } public Path newPath(Path relative) { final String[] absolute = new String[elements.length + relative.elements.length]; System.arraycopy(elements, 0, absolute, 0, elements.length); System.arraycopy(relative.elements, 0, absolute, elements.length, relative.elements.length); return new Path(absolute); } public String join(char separator) { StringBuilder builder = new StringBuilder(); for (String element : elements) { builder.append(separator); builder.append(element); } return builder.toString(); } /* ==================================================== */ @Override public String toString() { if (isRoot()) { return "/"; } if (asString == null) { asString = join('/'); } return asString; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Path)) { return false; } Path path = (Path)o; return Arrays.equals(elements, path.elements); } @Override public int hashCode() { int hash = hashCode; if (hash == 0) { hash = 8; hash = 31 * hash + Arrays.hashCode(elements); hashCode = hash; } return hash; } }