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

com.swoval.files.SimpleFileTreeView Maven / Gradle / Ivy

There is a newer version: 2.1.12
Show newest version
package com.swoval.files;

import com.swoval.functional.Filter;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystemLoopException;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

final class SimpleFileTreeView implements FileTreeView {
  /*
   * These constants must be kept in sync with the native quick list implementation
   */
  static final int UNKNOWN = Entries.UNKNOWN;
  static final int DIRECTORY = Entries.DIRECTORY;
  static final int FILE = Entries.FILE;
  static final int LINK = Entries.LINK;
  static final int NONEXISTENT = Entries.NONEXISTENT;
  private final DirectoryLister directoryLister;
  private final boolean followLinks;

  SimpleFileTreeView(final DirectoryLister directoryLister, final boolean followLinks) {
    this.directoryLister = directoryLister;
    this.followLinks = followLinks;
  }

  @Override
  public List list(
      final Path path, final int maxDepth, final Filter filter)
      throws IOException {
    final List result = new ArrayList<>();
    final Set visited = (followLinks && maxDepth > 0) ? new HashSet() : null;
    listDirImpl(path, 1, maxDepth, result, filter, visited);
    if (visited != null) visited.clear();
    return result;
  }

  @Override
  public void close() {}

  static class ListResults {
    private final List directories = new ArrayList<>();
    private final List files = new ArrayList<>();
    private final List symlinks = new ArrayList<>();

    List getDirectories() {
      return directories;
    }

    List getFiles() {
      return files;
    }

    List getSymlinks() {
      return symlinks;
    }

    void addDir(final String dir) {
      directories.add(dir);
    }

    void addFile(final String file) {
      files.add(file);
    }

    void addSymlink(final String link) {
      symlinks.add(link);
    }

    @Override
    public String toString() {
      return "ListResults(\n  directories = "
          + directories
          + ",\n  files = "
          + files
          + ", \n  symlinks = "
          + symlinks
          + "\n)";
    }
  }

  private int getSymbolicLinkTargetKind(final Path path, final boolean followLinks)
      throws IOException {
    if (followLinks) {
      try {
        final BasicFileAttributes attrs = NioWrappers.readAttributes(path);
        return LINK | (attrs.isDirectory() ? DIRECTORY : attrs.isRegularFile() ? FILE : UNKNOWN);
      } catch (final NoSuchFileException e) {
        return NONEXISTENT;
      }
    } else {
      return LINK;
    }
  }

  private void listDirImpl(
      final Path dir,
      final int depth,
      final int maxDepth,
      final List result,
      final Filter filter,
      final Set visited)
      throws IOException {
    if (visited != null) visited.add(dir);
    final SimpleFileTreeView.ListResults listResults =
        directoryLister.apply(dir.toString(), followLinks);
    final Iterator it = listResults.getDirectories().iterator();
    while (it.hasNext()) {
      final String part = it.next();
      if (!part.equals(".") && !part.equals("..")) {
        final Path path = Paths.get(dir + File.separator + part);
        final TypedPath file = TypedPaths.get(path, DIRECTORY);
        if (filter.accept(file)) {
          result.add(file);
          if (depth < maxDepth) {
            listDirImpl(path, depth + 1, maxDepth, result, filter, visited);
          }
        }
      }
    }
    final Iterator fileIt = listResults.getFiles().iterator();
    while (fileIt.hasNext()) {
      final TypedPath typedPath =
          TypedPaths.get(Paths.get(dir + File.separator + fileIt.next()), FILE);
      if (filter.accept(typedPath)) {
        result.add(typedPath);
      }
    }
    final Iterator symlinkIt = listResults.getSymlinks().iterator();
    while (symlinkIt.hasNext()) {
      final Path fileName = Paths.get(dir + File.separator + symlinkIt.next());
      final TypedPath typedPath =
          TypedPaths.get(fileName, getSymbolicLinkTargetKind(fileName, followLinks));
      if (filter.accept(typedPath)) {
        result.add(typedPath);
        if (typedPath.isDirectory() && depth < maxDepth && visited != null) {
          if (visited.add(typedPath.getPath().toRealPath())) {
            listDirImpl(fileName, depth + 1, maxDepth, result, filter, visited);
          } else {
            throw new FileSystemLoopException(fileName.toString());
          }
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy