Java tutorial
/* * Copyright 2016-present Facebook, Inc. * * 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.facebook.buck.jvm.java; import com.facebook.buck.io.PathListing; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.BiFunction; import java.util.function.Function; import java.util.List; import java.util.Locale; public class ClasspathChecker { private static final ImmutableSet<String> ALLOWED_EXTENSIONS_SET = ImmutableSet.of("jar", "zip"); private final String separator; private final String pathSeparator; private final Function<String, Path> toPathFunc; private final Function<Path, Boolean> isDirectoryFunc; private final Function<Path, Boolean> isFileFunc; private final BiFunction<Path, String, Iterable<Path>> globberFunc; public ClasspathChecker() { this(File.separator, File.pathSeparator, Paths::get, Files::isDirectory, Files::isRegularFile, (path, glob) -> { try { return PathListing.listMatchingPaths(path, glob, PathListing.GET_PATH_MODIFIED_TIME); } catch (IOException e) { throw new UncheckedIOException(e); } }); } @VisibleForTesting ClasspathChecker(String separator, String pathSeparator, Function<String, Path> toPathFunc, Function<Path, Boolean> isDirectoryFunc, Function<Path, Boolean> isFileFunc, BiFunction<Path, String, Iterable<Path>> globberFunc) { this.separator = separator; this.pathSeparator = pathSeparator; this.toPathFunc = toPathFunc; this.isDirectoryFunc = isDirectoryFunc; this.isFileFunc = isFileFunc; this.globberFunc = globberFunc; } /** * Parses a Java classpath string ("path/to/foo:baz.jar:blech.zip:path/to/*") * and checks if at least one entry is valid (exists on disk). * * From http://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html : * * Class path entries can contain the basename wildcard character *, * which is considered equivalent to specifying a list of all the * files in the directory with the extension .jar or .JAR. For * example, the class path entry foo/* specifies all JAR files in the * directory named foo. A classpath entry consisting simply of * * expands to a list of all the jar files in the current directory. */ public boolean validateClasspath(String classpath) { for (String entry : Splitter.on(pathSeparator).split(classpath)) { // On Windows, Path.endsWith("*") throws an error: // // java.nio.file.InvalidPathException: Illegal char <*> at index 0 // // So, we split manually. List<String> classpathComponents = Splitter.on(separator).splitToList(entry); if (classpathComponents.isEmpty()) { continue; } if (Iterables.getLast(classpathComponents).equals("*")) { // Trim the * off the path. List<String> dirComponents = classpathComponents.subList(0, classpathComponents.size() - 1); Path entryDir = toPathFunc.apply(Joiner.on(separator).join(dirComponents)); if (!Iterables.isEmpty(globberFunc.apply(entryDir, "*.jar"))) { return true; } else if (!Iterables.isEmpty(globberFunc.apply(entryDir, "*.JAR"))) { return true; } } else { Path entryPath = toPathFunc.apply(entry); if (isDirectoryFunc.apply(entryPath)) { return true; } else if (isFileFunc.apply(entryPath) && ALLOWED_EXTENSIONS_SET.contains( com.google.common.io.Files.getFileExtension(entryPath.toString().toLowerCase(Locale.US)))) { return true; } } } return false; } }