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.filesystem; 017 018import io.avaje.classpath.scanner.Resource; 019import io.avaje.classpath.scanner.core.Location; 020import io.avaje.classpath.scanner.internal.ScanLog; 021import org.slf4j.Logger; 022 023import java.io.File; 024import java.util.*; 025import java.util.function.Predicate; 026 027/** 028 * FileSystem scanner. 029 */ 030public class FileSystemScanner { 031 032 private static final Logger log = ScanLog.log; 033 034 /** 035 * Scans the FileSystem for resources under the specified location, starting with the specified prefix and ending with 036 * the specified suffix. 037 * 038 * @param location The location in the filesystem to start searching. Subdirectories are also searched. 039 * @param predicate The predicate used to match resources. 040 * @return The resources that were found. 041 */ 042 public List<Resource> scanForResources(Location location, Predicate<String> predicate) { 043 String path = location.path(); 044 File dir = new File(path); 045 if (!dir.isDirectory() || !dir.canRead()) { 046 log.debug("Unable to resolve location filesystem: {}", path); 047 return Collections.emptyList(); 048 } 049 List<Resource> resources = new ArrayList<>(); 050 for (String resourceName : findResourceNames(path, predicate)) { 051 resources.add(new FileSystemResource(resourceName)); 052 } 053 return resources; 054 } 055 056 /** 057 * Finds the resources names present at this location and below on the classpath starting with this prefix and 058 * ending with this suffix. 059 */ 060 private Set<String> findResourceNames(String path, Predicate<String> predicate) { 061 Set<String> resourceNames = findResourceNamesFromFileSystem(path, new File(path)); 062 return filterResourceNames(resourceNames, predicate); 063 } 064 065 /** 066 * Finds all the resource names contained in this file system folder. 067 * 068 * @param scanRootLocation The root location of the scan on disk. 069 * @param folder The folder to look for resources under on disk. 070 * @return The resource names; 071 */ 072 Set<String> findResourceNamesFromFileSystem(String scanRootLocation, File folder) { 073 log.trace("scan path: {} ({})", folder.getPath(), scanRootLocation); 074 Set<String> resourceNames = new TreeSet<>(); 075 076 File[] files = folder.listFiles(); 077 if (files != null) { 078 for (File file : files) { 079 if (file.canRead()) { 080 if (file.isDirectory()) { 081 resourceNames.addAll(findResourceNamesFromFileSystem(scanRootLocation, file)); 082 } else { 083 resourceNames.add(file.getPath()); 084 } 085 } 086 } 087 } 088 return resourceNames; 089 } 090 091 /** 092 * Filters this list of resource names to only include the ones whose filename matches this prefix and this suffix. 093 */ 094 private Set<String> filterResourceNames(Set<String> resourceNames, Predicate<String> predicate) { 095 Set<String> filteredResourceNames = new TreeSet<>(); 096 for (String resourceName : resourceNames) { 097 if (predicate.test(resourceName)) { 098 filteredResourceNames.add(resourceName); 099 } 100 } 101 return filteredResourceNames; 102 } 103}