001/*
002  Copyright 2010-2016 Boxfuse GmbH
003  <p/>
004  Licensed under the Apache License, Version 2.0 (the "License");
005  you may not use this file except in compliance with the License.
006  You may obtain a copy of the License at
007  <p/>
008  http://www.apache.org/licenses/LICENSE-2.0
009  <p/>
010  Unless required by applicable law or agreed to in writing, software
011  distributed under the License is distributed on an "AS IS" BASIS,
012  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  See the License for the specific language governing permissions and
014  limitations under the License.
015 */
016package io.avaje.classpath.scanner.internal.scanner.classpath;
017
018import io.avaje.classpath.scanner.internal.ScanLog;
019import io.avaje.classpath.scanner.internal.UrlUtils;
020import org.slf4j.Logger;
021
022import java.io.File;
023import java.net.URL;
024import java.util.Set;
025import java.util.TreeSet;
026
027/**
028 * ClassPathLocationScanner for the file system.
029 */
030public class FileSystemClassPathLocationScanner implements ClassPathLocationScanner {
031  private static final Logger log = ScanLog.log;
032
033  public Set<String> findResourceNames(String location, URL locationUrl) {
034    String filePath = UrlUtils.toFilePath(locationUrl);
035    File folder = new File(filePath);
036    if (!folder.isDirectory()) {
037      log.trace("skip as not a directory: {}", filePath);
038      return new TreeSet<>();
039    }
040    String classPathRootOnDisk = filePath.substring(0, filePath.length() - location.length());
041    if (!classPathRootOnDisk.endsWith(File.separator)) {
042      classPathRootOnDisk = classPathRootOnDisk + File.separator;
043    }
044    log.trace("scan starting at root in filesystem: {}", classPathRootOnDisk);
045    return findResourceNamesFromFileSystem(classPathRootOnDisk, location, folder);
046  }
047
048  /**
049   * Finds all the resource names contained in this file system folder.
050   *
051   * @param classPathRootOnDisk The location of the classpath root on disk, with a trailing slash.
052   * @param scanRootLocation    The root location of the scan on the classpath, without leading or trailing slashes.
053   * @param folder              The folder to look for resources under on disk.
054   * @return The resource names;
055   */
056  Set<String> findResourceNamesFromFileSystem(String classPathRootOnDisk, String scanRootLocation, File folder) {
057    log.trace("scan resources in path: {} ({})", folder.getPath(), scanRootLocation);
058    Set<String> resourceNames = new TreeSet<>();
059
060    File[] files = folder.listFiles();
061    if (files != null) {
062      for (File file : files) {
063        if (file.canRead()) {
064          String resourcePath = toResourceNameOnClasspath(classPathRootOnDisk, file);
065          if (file.isDirectory()) {
066            if (!ignorePath(resourcePath)) {
067              resourceNames.addAll(findResourceNamesFromFileSystem(classPathRootOnDisk, scanRootLocation, file));
068            }
069          } else {
070            resourceNames.add(resourcePath);
071          }
072        }
073      }
074    }
075    return resourceNames;
076  }
077
078  private boolean ignorePath(String resourcePath) {
079    return resourcePath.startsWith("io/avaje/classpath") || resourcePath.startsWith("io/ebean");
080  }
081
082  /**
083   * Converts this file into a resource name on the classpath.
084   *
085   * @param classPathRootOnDisk The location of the classpath root on disk, with a trailing slash.
086   * @param file                The file.
087   * @return The resource name on the classpath.
088   */
089  private String toResourceNameOnClasspath(String classPathRootOnDisk, File file) {
090    String fileName = file.getAbsolutePath().replace("\\", "/");
091    //Cut off the part on disk leading to the root of the classpath
092    //This leaves a resource name starting with the scanRootLocation,
093    //   with no leading slash, containing subDirs and the fileName.
094    return fileName.substring(classPathRootOnDisk.length());
095  }
096}