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