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}