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