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

com.github.rinde.rinsim.io.FileProvider Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/*
 * Copyright (C) 2011-2017 Rinde van Lon, imec-DistriNet, KU Leuven
 *
 * Licensed 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 com.github.rinde.rinsim.io;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Verify.verifyNotNull;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newLinkedHashSet;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

/**
 * Configurable supplier of files.
 * @author Rinde van Lon
 * @param  The type of object that this file provider provides. See
 *          {@link Builder#build()} and {@link Builder#build(Function)} for more
 *          details.
 */
public final class FileProvider implements Supplier> {
  final ImmutableList roots;
  final Predicate pathPredicate;
  final Function pathReader;

  FileProvider(ImmutableList rootPaths, Predicate predicate,
      Function reader) {
    roots = rootPaths;
    pathPredicate = predicate;
    pathReader = reader;
  }

  @Override
  public ImmutableSet get() {
    try {
      final PathCollector pc = new PathCollector<>(pathPredicate,
        pathReader);
      for (final Path path : roots) {
        Files.walkFileTree(path, pc);
      }
      return pc.getResults();
    } catch (final IOException e) {
      throw new IllegalStateException(e);
    }
  }

  /**
   * @return A new {@link Builder} for creating a {@link FileProvider} instance.
   */
  public static Builder builder() {
    return new Builder();
  }

  /**
   * A builder for creating {@link FileProvider} instances. Via this builder
   * files and directories can be added and filtered. The resulting
   * {@link FileProvider} will provide all specified files.
   *
   * @author Rinde van Lon
   */
  public static class Builder {
    Predicate pathPredicate;
    final List paths;

    Builder() {
      pathPredicate = Predicates.alwaysTrue();
      paths = newArrayList();
    }

    /**
     * Add the file or directory that is represented by this {@link Path}
     * instance. If it is a directory it will be added recursively. Each added
     * file will be included at maximum once.
     *
     * @param path The file or directory to add.
     * @return This, as per the builder pattern.
     */
    public Builder add(Path path) {
      checkArgument(Files.exists(path), "Invalid path: '%s'.", path);
      paths.add(path);
      return this;
    }

    /**
     * Adds all files or directories that are represented by the specified
     * {@link Path}s. Directories will be added recursively. Each added file
     * will be included at maximum once.
     *
     * @param ps The files and/or directories to add.
     * @return This, as per the builder pattern.
     */
    public Builder add(Iterable ps) {
      for (final Path p : ps) {
        add(p);
      }
      return this;
    }

    /**
     * Apply a filter to all added and to be added paths. The expected syntax is
     * the same as for the
     * {@link java.nio.file.FileSystem#getPathMatcher(String)} method. Only one
     * filter can be applied at one time.
     *
     * @param syntaxAndPattern The syntax and pattern.
     * @return This, as per the builder pattern.
     */
    public Builder filter(String syntaxAndPattern) {
      checkNotNull(syntaxAndPattern);
      pathPredicate = new PredicateAdapter(syntaxAndPattern, FileSystems
        .getDefault().getPathMatcher(syntaxAndPattern));
      return this;
    }

    /**
     * Apply the specified {@link PathMatcher} as a filter. Only files that
     * satisfy the filter will be included.Only one filter can be applied at one
     * time.
     *
     * @param matcher The matcher to use as filter.
     * @return This, as per the builder pattern.
     */
    public Builder filter(PathMatcher matcher) {
      checkNotNull(matcher);
      pathPredicate = new PredicateAdapter(matcher);
      return this;
    }

    /**
     * Apply the specified {@link Predicate} as a filter. Only files that
     * satisfy the filter will be included. Only one filter can be applied at
     * one time.
     *
     * @param predicate The predicate to use as filter.
     * @return This, as per the builder pattern.
     */
    public Builder filter(Predicate predicate) {
      checkNotNull(predicate);
      pathPredicate = predicate;
      return this;
    }

    /**
     * Activates the command-line interface for this builder. If an invalid
     * option is given the help will be printed automatically to
     * {@link System#out}.
     *
     * @param stream The stream to write error messages to if any.
     * @param args The command-line arguments.
     * @return This, as per the builder pattern.
     */
    public Builder cli(PrintStream stream, String... args) {
      final Optional error = FileProviderCli.execute(this, args);
      if (error.isPresent()) {
        stream.println(error.get());
      }
      return this;
    }

    /**
     * Create a new {@link FileProvider} which will provide the {@link Path} s
     * as specified by this builder.
     *
     * @return The new {@link FileProvider} instance.
     */
    public FileProvider build() {
      return build(Functions.identity());
    }

    /**
     * Create a new {@link FileProvider} which will provide the converted
     * {@link Path}s as specified by this builder. Each path will be converted
     * to type T using the specified converter.
     *
     * @param converter A {@link Function} that converts {@link Path}s.
     * @param  The type to which {@link Path}s are converted and which will
     *          be provided by the {@link FileProvider}.
     * @return The new {@link FileProvider} instance.
     */
    public  FileProvider build(Function converter) {
      checkNotNull(converter);
      checkArgument(!paths.isEmpty(), "No paths are specified.");
      return new FileProvider<>(ImmutableList.copyOf(paths),
        pathPredicate, converter);
    }

    int getNumberOfFiles() {
      if (paths.isEmpty()) {
        return 0;
      }
      return build().get().size();
    }
  }

  static class PathCollector extends SimpleFileVisitor {
    final Set convertedPaths;
    final Predicate pathPredicate;
    final Function pathReader;

    PathCollector(Predicate predicate, Function reader) {
      convertedPaths = newLinkedHashSet();
      pathPredicate = predicate;
      pathReader = reader;
    }

    @Override
    public FileVisitResult visitFile(@Nullable Path file,
        @Nullable BasicFileAttributes attrs)
            throws IOException {
      if (pathPredicate.apply(file)) {
        convertedPaths.add(verifyNotNull(pathReader.apply(file), "%s",
          pathReader));
      }
      return FileVisitResult.CONTINUE;
    }

    public ImmutableSet getResults() {
      return ImmutableSet.copyOf(convertedPaths);
    }
  }

  static class PredicateAdapter implements Predicate {
    private final PathMatcher delegate;
    private final Optional name;

    PredicateAdapter(String nm, PathMatcher matcher) {
      name = Optional.of(nm);
      delegate = matcher;
    }

    PredicateAdapter(PathMatcher matcher) {
      name = Optional.absent();
      delegate = matcher;
    }

    @Override
    public boolean apply(@Nullable Path input) {
      return delegate.matches(input);
    }

    @Override
    public String toString() {
      if (name.isPresent()) {
        return name.get();
      }
      return delegate.toString();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy