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

org.smallmind.file.ephemeral.EphemeralPath Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2007 through 2024 David Berkman
 *
 * This file is part of the SmallMind Code Project.
 *
 * The SmallMind Code Project is free software, you can redistribute
 * it and/or modify it under either, at your discretion...
 *
 * 1) The terms of GNU Affero General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * ...or...
 *
 * 2) The terms of the Apache License, Version 2.0.
 *
 * The SmallMind Code Project 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
 * General Public License or Apache License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * and the Apache License along with the SmallMind Code Project. If not, see
 *  or .
 *
 * Additional permission under the GNU Affero GPL version 3 section 7
 * ------------------------------------------------------------------
 * If you modify this Program, or any covered work, by linking or
 * combining it with other code, such other code is not for that reason
 * alone subject to any of the requirements of the GNU Affero GPL
 * version 3.
 */
package org.smallmind.file.ephemeral;

import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Arrays;
import java.util.LinkedList;
import org.smallmind.file.ephemeral.watch.EphemeralWatchKey;
import org.smallmind.file.ephemeral.watch.EphemeralWatchService;

public class EphemeralPath implements Path {

  private static final String[] NO_NAMES = new String[0];
  private static final String SEPARATOR = "/";
  private final EphemeralFileSystem fileSystem;
  private final String[] names;
  private final boolean absolute;

  protected EphemeralPath (EphemeralFileSystem fileSystem) {

    this.fileSystem = fileSystem;

    absolute = true;
    names = NO_NAMES;
  }

  public EphemeralPath (EphemeralFileSystem fileSystem, String first, String... more) {

    this.fileSystem = fileSystem;

    if (first == null) {
      throw new NullPointerException();
    } else {

      LinkedList nameList = new LinkedList<>();

      absolute = first.startsWith(SEPARATOR);

      split(nameList, first, absolute);

      if ((more != null) && (more.length > 0)) {
        for (String another : more) {
          split(nameList, another, false);
        }
      }

      names = nameList.toArray(new String[0]);
    }
  }

  private EphemeralPath (EphemeralPath path, int begin, int end) {

    fileSystem = (EphemeralFileSystem)path.getFileSystem();
    absolute = path.isAbsolute();
    names = new String[end - begin];
    int to = 0;

    for (int from = begin; from < end; from++) {
      names[to++] = path.getNames()[from];
    }
  }

  private EphemeralPath (EphemeralFileSystem fileSystem, String[] names, boolean absolute) {

    this.fileSystem = fileSystem;
    this.names = names;
    this.absolute = absolute;
  }

  public static char getSeparatorChar () {

    return SEPARATOR.charAt(0);
  }

  public static String getSeparator () {

    return SEPARATOR;
  }

  private void split (LinkedList nameList, String text, boolean absolute) {

    if (text.length() == 0) {
      throw new InvalidPathException(text, "Empty path component");
    } else {

      int index = 0;

      for (String segment : text.split(SEPARATOR, -1)) {
        if (segment.length() == 0) {
          if ((!absolute) || (index > 0)) {
            throw new InvalidPathException(text, "Empty path component");
          }
        } else {
          nameList.add(segment);
          index++;
        }
      }
    }
  }

  public String[] getNames () {

    return names;
  }

  @Override
  public FileSystem getFileSystem () {

    return fileSystem;
  }

  @Override
  public boolean isAbsolute () {

    return absolute;
  }

  @Override
  public EphemeralPath getRoot () {

    return absolute ? new EphemeralPath(fileSystem) : null;
  }

  @Override
  public EphemeralPath getFileName () {

    return (names.length == 0) ? null : new EphemeralPath(fileSystem, names[names.length - 1]);
  }

  @Override
  public EphemeralPath getParent () {

    return (names.length == 0) ? null : (names.length > 1) ? new EphemeralPath(this, 0, names.length - 1) : absolute ? new EphemeralPath(fileSystem) : null;
  }

  @Override
  public int getNameCount () {

    return names.length;
  }

  @Override
  public EphemeralPath getName (int index) {

    if ((index < 0) || (index >= names.length)) {
      throw new IllegalArgumentException("Illegal index value");
    }

    return new EphemeralPath(fileSystem, names[index]);
  }

  @Override
  public EphemeralPath subpath (int beginIndex, int endIndex) {

    if ((beginIndex < 0) || (beginIndex >= names.length) || (endIndex <= beginIndex) || (endIndex > names.length)) {
      throw new IllegalArgumentException("Illegal index value");
    } else {

      return new EphemeralPath(this, beginIndex, endIndex);
    }
  }

  @Override
  public boolean startsWith (Path other) {

    if ((other.getFileSystem() instanceof EphemeralFileSystem) && (other.getNameCount() <= names.length)) {
      for (int index = 0; index < other.getNameCount(); index++) {
        if (!((EphemeralPath)other).getNames()[index].equals(names[index])) {

          return false;
        }
      }

      return true;
    }

    return false;
  }

  @Override
  public boolean endsWith (Path other) {

    if (other.getFileSystem() instanceof EphemeralFileSystem) {
      if (absolute || (!other.isAbsolute())) {
        if ((other.isAbsolute() && (other.getNameCount() == names.length)) || ((!other.isAbsolute()) && (other.getNameCount() <= names.length))) {

          int offset = names.length - other.getNameCount();

          for (int index = 0; index < other.getNameCount(); index++) {
            if (!((EphemeralPath)other).getNames()[index].equals(names[offset + index])) {

              return false;
            }
          }

          return true;
        }
      }
    }

    return false;
  }

  @Override
  public EphemeralPath normalize () {

    LinkedList namesList = null;
    int position = 0;

    for (String name : names) {
      switch (name) {
        case ".":
          if (namesList == null) {
            namesList = new LinkedList<>(Arrays.asList(names).subList(0, position));
          }
          break;
        case "..":
          if (namesList == null) {
            namesList = (position > 1) ? new LinkedList<>(Arrays.asList(names).subList(0, position - 1)) : new LinkedList<>();
          } else if (!namesList.isEmpty()) {
            namesList.removeLast();
          }
          break;
        default:
          if (namesList == null) {
            position++;
          } else {
            namesList.add(name);
          }
      }
    }

    return (namesList == null) ? this : new EphemeralPath(fileSystem, namesList.toArray(new String[0]), absolute);
  }

  @Override
  public Path resolve (Path other) {

    if (other.isAbsolute()) {

      return other;
    } else if (other.getNameCount() == 0) {

      return this;
    } else {

      String[] resolvedNames = new String[names.length + other.getNameCount()];

      System.arraycopy(names, 0, resolvedNames, 0, names.length);
      for (int index = 0; index < other.getNameCount(); index++) {
        resolvedNames[names.length + index] = other.getName(index).toString();
      }

      return new EphemeralPath(fileSystem, resolvedNames, absolute);
    }
  }

  @Override
  public EphemeralPath relativize (Path other) {

    if (absolute != other.isAbsolute()) {
      throw new IllegalArgumentException("No relative path can be constructed");
    } else {

      LinkedList namesList = new LinkedList<>();
      int index = 0;

      for (String name : names) {
        if (name.equals(other.getName(index).toString())) {
          index++;
        } else {
          break;
        }
      }

      if (index < names.length) {

        int redacted = names.length - index;

        for (int loop = 0; loop < redacted; loop++) {
          namesList.add("..");
        }
      }

      if (index < other.getNameCount()) {
        for (int loop = index; loop < other.getNameCount(); loop++) {
          namesList.add(other.getName(loop).toString());
        }
      }

      return new EphemeralPath(fileSystem, namesList.toArray(new String[0]), false);
    }
  }

  @Override
  public URI toUri () {

    return URI.create(fileSystem.provider().getScheme() + "://" + toAbsolutePath());
  }

  @Override
  public EphemeralPath toAbsolutePath () {

    return absolute ? this : new EphemeralPath(fileSystem, names, true);
  }

  @Override
  public EphemeralPath toRealPath (LinkOption... options) {

    // TODO: will need to handle symlinks when/if the file system provide for them
    return normalize().toAbsolutePath();
  }

  @Override
  public WatchKey register (WatchService watcher, WatchEvent.Kind[] events, WatchEvent.Modifier... modifiers)
    throws NoSuchFileException, NotDirectoryException {

    if (!(watcher instanceof EphemeralWatchService)) {
      throw new IllegalArgumentException("The watcher is not associated with this file system");
    } else {

      EphemeralWatchKey watchKey;

      // modifiers unused as yet
      ((EphemeralWatchService)watcher).register(watchKey = new EphemeralWatchKey((EphemeralWatchService)watcher, events, this));

      return watchKey;
    }
  }

  @Override
  public int compareTo (Path other) {

    EphemeralPath otherEphemeralPath = (EphemeralPath)other;

    if (names.length == other.getNameCount()) {
      for (int index = 0; index < names.length; index++) {

        int comparison;

        if ((comparison = names[index].compareTo(otherEphemeralPath.getNames()[index])) != 0) {

          return comparison;
        }
      }

      return 0;
    } else {

      return names.length - otherEphemeralPath.getNameCount();
    }
  }

  @Override
  public int hashCode () {

    return (Arrays.hashCode(names) * 31) + (absolute ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode());
  }

  @Override
  public boolean equals (Object obj) {

    return (obj instanceof EphemeralPath) && (((EphemeralPath)obj).isAbsolute() == absolute) && Arrays.equals(((EphemeralPath)obj).getNames(), names);
  }

  @Override
  public String toString () {

    StringBuilder pathBuilder = new StringBuilder();

    for (String name : names) {
      if (absolute || (pathBuilder.length() > 0)) {
        pathBuilder.append(SEPARATOR);
      }
      pathBuilder.append(name);
    }

    return pathBuilder.toString();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy