com.quigley.filesystem.FilesystemPath.java Source code

Java tutorial

Introduction

Here is the source code for com.quigley.filesystem.FilesystemPath.java

Source

/*
This file is part of Filesystem.
    
Filesystem is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
    
Filesystem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.
    
You should have received a copy of the GNU Lesser General Public
License along with Moose.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.quigley.filesystem;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.quigley.filesystem.json.FilesystemPathDeserializer;
import com.quigley.filesystem.json.FilesystemPathSerializer;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

@JsonSerialize(using = FilesystemPathSerializer.class)
@JsonDeserialize(using = FilesystemPathDeserializer.class)
public class FilesystemPath implements Comparable<FilesystemPath> {

    /*
     * Constructors
     */

    public FilesystemPath(String pathString) {
        pathString = FilesystemPath.normalize(pathString);
        if (pathString.length() == 0) {
            isAbsolute = true;
            elements = new ArrayList<String>();
        } else if (pathString.substring(0, 1).equals("/")) {
            isAbsolute = true;
            pathString = pathString.substring(1, pathString.length());
        }
        if (pathString.length() > 0) {
            String[] componentArray = pathString.split("/");
            elements = new ArrayList<String>(componentArray.length);
            for (String component : componentArray) {
                elements.add(component);
            }
        }
        if (elements.size() > 0 && elements.get(0).matches("[a-zA-Z]\\:")) {
            isAbsolute = true;
        }
    }

    public FilesystemPath(FilesystemPath source) {
        elements = new LinkedList<String>();
        for (int i = 0; i < source.size(); i++) {
            elements.add(source.get(i));
        }
        isAbsolute = source.isAbsolute;
    }

    public FilesystemPath(List<String> elements) {
        this.elements = elements;
    }

    /*
     * Absolute
     */

    public FilesystemPath makeAbsolute() {
        FilesystemPath absolutePath = new FilesystemPath(this.asFile().getAbsolutePath()).setAbsolute(true);
        return absolutePath;
    }

    public boolean isAbsolute() {
        return isAbsolute;
    }

    public FilesystemPath setAbsolute(boolean absolute) {
        FilesystemPath absolutePath = new FilesystemPath(elements);
        absolutePath.isAbsolute = true;
        return absolutePath;
    }

    /*
     * Modifiers
     */

    public FilesystemPath add(String element) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy.add(element);

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath add(FilesystemPath p) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        for (int i = 0; i < p.size(); i++) {
            elementsCopy.add(p.get(i));
        }

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath set(int idx, String component) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy.set(idx, component);

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath remove(int idx) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy.remove(idx);

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath removeFirst() {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy.remove(0);

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath removeFirst(int count) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy = elementsCopy.subList(count, elementsCopy.size());

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath removeLast() {
        List<String> elementsCopy = new ArrayList<String>(elements);

        elementsCopy.remove(elements.size() - 1);

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath setLast(String last) {
        List<String> elementsCopy = new ArrayList<String>(elements);

        if (elementsCopy.size() > 0) {
            elementsCopy.set(elementsCopy.size() - 1, last);

        } else {
            elementsCopy.add(last);
        }

        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath tail(int startIndex) {
        if (startIndex < 0) {
            throw new FilesystemException("Tail before start");
        }
        if (startIndex >= elements.size()) {
            throw new FilesystemException("Tail past end");
        }
        List<String> tail = new ArrayList<>();
        for (int i = startIndex; i < elements.size(); i++) {
            tail.add(elements.get(i));
        }
        return new FilesystemPath(tail);
    }

    public FilesystemPath removeCommonParent(FilesystemPath otherPath) {
        FilesystemPath outputPath = this;
        FilesystemPath parallelPath = otherPath;

        while (outputPath.size() > 0 && parallelPath.size() > 0 && outputPath.get(0).equals(parallelPath.get(0))) {
            outputPath = outputPath.removeFirst();
            parallelPath = parallelPath.removeFirst();
        }

        if (!outputPath.equals(otherPath)) {
            outputPath.isAbsolute = false;
        }

        return outputPath;
    }

    public FilesystemPath simplify() {
        List<String> elementsCopy = new ArrayList<String>(elements);
        ListIterator<String> i = elementsCopy.listIterator();
        boolean saw = false;
        while (i.hasNext()) {
            String value = i.next();
            if (value.equals(".")) {
                i.remove();
            } else if (value.equals("..")) {
                if (saw) {
                    if (i.hasPrevious()) {
                        i.remove();
                        i.previous();
                        i.remove();
                    }
                }
            } else {
                saw = true;
            }
        }
        FilesystemPath pathCopy = new FilesystemPath(elementsCopy);
        pathCopy.isAbsolute = isAbsolute;

        return pathCopy;
    }

    public FilesystemPath navigate(FilesystemPath destination) {
        if (destination == null) {
            throw new FilesystemException("Cannot navigate to null path");
        }
        if (this.isAbsolute() != destination.isAbsolute()) {
            throw new FilesystemException("Absolute/non-absolute mismatch");
        }

        int divergencePoint = 0;
        for (; divergencePoint < elements.size() && divergencePoint < destination.size(); divergencePoint++) {
            if (!elements.get(divergencePoint).equals(destination.get(divergencePoint)))
                break;
        }

        List<String> relativeElements = new ArrayList<>();
        for (int i = 0; i < (elements.size() - 1 - divergencePoint); i++) {
            relativeElements.add("..");
        }

        FilesystemPath destinationTail = destination.tail(divergencePoint);
        relativeElements.addAll(destinationTail.elements);

        FilesystemPath relative = new FilesystemPath(relativeElements);
        return relative;
    }

    /*
     * Component Accessors
     */

    public FilesystemPath parent() {
        return removeLast();
    }

    public int size() {
        return elements.size();
    }

    public String get(int index) {
        return elements.get(index);
    }

    public String getLast() {
        if (size() > 0) {
            return elements.get(elements.size() - 1);

        } else {
            return null;
        }
    }

    /*
     * Extension
     */

    public String getExtension() {
        if (elements.size() < 1) {
            return null;
        }
        String element = elements.get(elements.size() - 1);
        int extStart = element.lastIndexOf(".");
        if (extStart != -1) {
            return element.substring(extStart + 1);
        } else {
            return null;
        }
    }

    public FilesystemPath removeExtension() {
        FilesystemPath pathCopy = new FilesystemPath(removeExtension(this.toString()));
        pathCopy.isAbsolute = isAbsolute;
        return pathCopy;
    }

    public FilesystemPath setExtension(String extension) {
        FilesystemPath pathCopy = new FilesystemPath(removeExtension(this.toString()));
        pathCopy = new FilesystemPath(pathCopy.toString() + "." + extension);
        pathCopy.isAbsolute = isAbsolute;
        return pathCopy;
    }

    public FilesystemPath addExtension(String extension) {
        FilesystemPath pathCopy = new FilesystemPath(this.toString() + "." + extension);
        pathCopy.isAbsolute = isAbsolute;
        return pathCopy;
    }

    /*
     * Matching
     */

    public boolean contains(String match) {
        for (String element : elements) {
            if (element.equals(match)) {
                return true;
            }
        }
        return false;
    }

    public boolean startsWith(FilesystemPath otherPath) {
        if (otherPath == null) {
            return false;
        }
        if (elements.size() >= otherPath.size()) {
            for (int i = 0; i < otherPath.size(); i++) {
                if (!elements.get(i).equals(otherPath.get(i))) {
                    return false;
                }
            }
            return true;

        } else {
            return false;
        }
    }

    public File asFile() {
        return new File(this.toString());
    }

    public Path asPath() {
        return asFile().toPath();
    }

    @Override
    public int compareTo(FilesystemPath arg0) {
        return toString().compareTo(arg0.toString());
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((elements == null) ? 0 : elements.hashCode());
        result = prime * result + (isAbsolute ? 1231 : 1237);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final FilesystemPath other = (FilesystemPath) obj;
        if (elements == null) {
            if (other.elements != null)
                return false;
        } else if (!elements.equals(other.elements))
            return false;
        if (isAbsolute != other.isAbsolute)
            return false;
        return true;
    }

    public String toString() {
        boolean leadingSlash = isAbsolute;
        if (isAbsolute && elements.size() > 0 && elements.get(0).matches("[a-zA-Z]\\:")) {
            leadingSlash = false;
        }

        boolean trailingSlash = false;
        if (elements.size() == 1 && elements.get(0).matches("[a-zA-Z]\\:")) {
            trailingSlash = true;
        }

        StringBuilder sb = new StringBuilder();
        if (leadingSlash) {
            sb.append("/");
        }
        for (int i = 0; i < elements.size(); i++) {
            if (i > 0) {
                sb.append("/");
            }
            sb.append(elements.get(i));
        }
        if (trailingSlash) {
            sb.append("/");
        }

        return sb.toString();
    }

    private boolean isAbsolute;
    private List<String> elements;

    /*
     * Static Operations
     */

    public static FilesystemPath currentWorkingDirectory() {
        File cwd = new File(".");
        return new FilesystemPath(cwd.getAbsolutePath()).setAbsolute(true).simplify();
    }

    public static String normalize(String pathString) {
        while (pathString.indexOf("\\") != -1) {
            pathString = pathString.replace('\\', '/');
        }
        while (pathString.indexOf("//") != -1) {
            pathString = pathString.replace("//", "/");
        }
        if (pathString.lastIndexOf("/") == (pathString.length() - 1)) {
            pathString = pathString.substring(0, pathString.length() - 1);
        }
        return pathString;
    }

    private static String removeExtension(String pathString) {
        int extensionStartIndex = pathString.lastIndexOf(".");
        if (extensionStartIndex != -1) {
            return pathString.substring(0, extensionStartIndex);
        } else {
            return pathString;
        }
    }

    public static List<FilesystemPath> removeCommonParent(List<FilesystemPath> paths, FilesystemPath otherPath) {
        List<FilesystemPath> trimmedPaths = new ArrayList<FilesystemPath>();
        for (FilesystemPath path : paths) {
            trimmedPaths.add(path.removeCommonParent(otherPath));
        }
        return trimmedPaths;
    }
}