io.milton.common.Path Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) 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 io.milton.common;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
/**
* Immutable class which represents a path in the file system.
*/
public class Path implements Serializable {
private static final long serialVersionUID = -8411900835514833454L;
private final Path parent;
private final String name;
public static final Path root = new Path();
private int hash;
private final int length;
public static final LengthComparator LENGTH_COMPARATOR = new LengthComparator();
/**
* Method which creates and instance of Path.
* @param parent Path to parent.
* @param path relative path from parent.
* @return Path instance.
*/
public static Path path(Path parent, String path) {
if (path == null)
throw new NullPointerException("The path parameter may not be null");
return split(parent, path);
}
/**
* Method which creates and instance of Path.
* @param path relative path from root.
* @return Path instance.
*/
public static Path path(String path) {
if (path == null || path.isEmpty()) return root;
return split(null, path);
}
private static Path split(Path startFrom, String s) {
Path parent = startFrom;
StringBuilder sb = null;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '/':
if (i == 0) {
parent = root;
} else {
if (sb != null && sb.length() > 0) {
String ss = sb.toString();
if (parent != null) parent = parent.child(ss);
else parent = new Path(null, ss);
}
sb = null;
}
break;
// case ' ':
// // ignore
// break;
default:
if (sb == null) sb = new StringBuilder();
sb.append(c);
}
}
if (sb != null && sb.length() > 0) {
String ss = sb.toString();
if (parent != null) parent = parent.child(ss);
else parent = new Path(null, ss);
}
return parent;
}
private Path() {
this.parent = null;
this.name = null;
length = 0;
}
private Path(Path parent, String name) {
if (name == null)
throw new IllegalArgumentException("name may not be null");
this.parent = parent;
this.name = name;
if (this.parent != null) {
this.length = this.parent.length + 1;
} else {
this.length = 1;
}
}
public int getLength() {
return length;
}
public String[] getParts() {
String[] arr = new String[length];
Path p = this;
int i = length;
while (i > 0) {
arr[--i] = p.getName();
p = p.getParent();
}
return arr;
}
/**
* @return - the first part of the path. ie a/b/c returns a
*/
public String getFirst() {
Path p = this;
while (p.getParent() != null) {
Path next = p.getParent();
if (next.getName() == null) return p.getName();
p = next;
}
return p.getName();
}
public List getAfterFirst() {
List afterFirst = new ArrayList<>();
Path p = this;
while (p.getParent() != null && !p.getParent().isRoot()) {
afterFirst.add(0, p.getName());
p = p.getParent();
if (p == null) break;
}
return afterFirst;
}
public Path getStripFirst() {
return stripFirst(this);
}
Path stripFirst(Path p) {
Path pParent = p.getParent();
if (pParent == null || pParent.isRoot()) return root;
pParent = stripFirst(pParent);
return new Path(pParent, p.getName());
}
public String getName() {
return name;
}
public Path getParent() {
return parent;
}
public boolean isRoot() {
return ((parent == null) && (name == null));
}
public String toPath() {
if (isRoot()) return "";
if (parent == null) return name;
return parent.toString() + '/' + name;
}
@Override
public String toString() {
return toPath();
}
public String toString(String delimiter) {
if (parent == null) return "";
return parent.toString(delimiter) + delimiter + name;
}
public static Path root() {
return root;
}
@Override
public int hashCode() {
if (hash == 0) {
if (parent == null) {
hash = 158;
} else {
hash = parent.hashCode() ^ name.hashCode();
}
}
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj instanceof Path) {
Path p2 = (Path) obj;
if (this.isRoot()) {
return p2.isRoot();
} else {
if (parentEquals(this, p2)) {
return Objects.equals(this.name, p2.name);
} else {
return false;
}
}
} else {
return false;
}
}
private static boolean parentEquals(Path p1, Path p2) {
if (p2.parent == null) {
return p1.parent == null;
} else {
return p2.parent.equals(p1.parent);
}
}
public Path child(String name) {
return new Path(this, name);
}
public boolean isRelative() {
if (parent == null) {
return !isRoot();
} else {
return parent.isRelative();
}
}
/**
* Add the path components of the given path to this one.
*
* Eg "a/b/c" + "/d/e/f" = "a/b/c/d/e/f"
*
* @param p
* @return
*/
public Path add(Path p) {
Path x = this;
for (String s : p.getParts()) {
x = x.child(s);
}
return x;
}
public static class LengthComparator implements Comparator {
public int compare(Path o1, Path o2) {
Integer i1 = o1.getLength();
Integer i2 = o2.getLength();
return i1.compareTo(i2);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy