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.UrlUtils; 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 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 = LoggerFactory.getLogger(FileSystemClassPathLocationScanner.class); 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.debug("Skipping path as it is not a directory: " + filePath); 038 return new TreeSet<>(); 039 } 040 041 String classPathRootOnDisk = filePath.substring(0, filePath.length() - location.length()); 042 if (!classPathRootOnDisk.endsWith(File.separator)) { 043 classPathRootOnDisk = classPathRootOnDisk + File.separator; 044 } 045 LOG.debug("Scanning starting at classpath root in filesystem: " + classPathRootOnDisk); 046 return findResourceNamesFromFileSystem(classPathRootOnDisk, location, folder); 047 } 048 049 /** 050 * Finds all the resource names contained in this file system folder. 051 * 052 * @param classPathRootOnDisk The location of the classpath root on disk, with a trailing slash. 053 * @param scanRootLocation The root location of the scan on the classpath, without leading or trailing slashes. 054 * @param folder The folder to look for resources under on disk. 055 * @return The resource names; 056 */ 057 /*private -> for testing*/ 058 Set<String> findResourceNamesFromFileSystem(String classPathRootOnDisk, String scanRootLocation, File folder) { 059 LOG.debug("Scanning for resources in path: {} ({})", folder.getPath(), scanRootLocation); 060 061 Set<String> resourceNames = new TreeSet<>(); 062 063 File[] files = folder.listFiles(); 064 if (files != null) { 065 for (File file : files) { 066 if (file.canRead()) { 067 String resourcePath = toResourceNameOnClasspath(classPathRootOnDisk, file); 068 if (file.isDirectory()) { 069 if (!ignorePath(resourcePath)) { 070 resourceNames.addAll(findResourceNamesFromFileSystem(classPathRootOnDisk, scanRootLocation, file)); 071 } 072 } else { 073 resourceNames.add(resourcePath); 074 } 075 } 076 } 077 } 078 079 return resourceNames; 080 } 081 082 private boolean ignorePath(String resourcePath) { 083 return resourcePath.startsWith("org/avaje/classpath") || resourcePath.startsWith("io/ebean"); 084 } 085 086 /** 087 * Converts this file into a resource name on the classpath. 088 * 089 * @param classPathRootOnDisk The location of the classpath root on disk, with a trailing slash. 090 * @param file The file. 091 * @return The resource name on the classpath. 092 */ 093 private String toResourceNameOnClasspath(String classPathRootOnDisk, File file) { 094 String fileName = file.getAbsolutePath().replace("\\", "/"); 095 096 //Cut off the part on disk leading to the root of the classpath 097 //This leaves a resource name starting with the scanRootLocation, 098 // with no leading slash, containing subDirs and the fileName. 099 return fileName.substring(classPathRootOnDisk.length()); 100 } 101}