001/* 002 * Copyright 2012-2016 the original author or authors. 003 * 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 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 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 */ 016 017package org.springframework.boot.cli.util; 018 019import java.io.IOException; 020import java.net.MalformedURLException; 021import java.net.URL; 022import java.util.ArrayList; 023import java.util.LinkedHashSet; 024import java.util.List; 025import java.util.Set; 026 027import org.springframework.core.io.ClassPathResource; 028import org.springframework.core.io.DefaultResourceLoader; 029import org.springframework.core.io.FileSystemResourceLoader; 030import org.springframework.core.io.Resource; 031import org.springframework.core.io.UrlResource; 032import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 033import org.springframework.util.Assert; 034import org.springframework.util.ClassUtils; 035import org.springframework.util.StringUtils; 036 037/** 038 * Utilities for manipulating resource paths and URLs. 039 * 040 * @author Dave Syer 041 * @author Phillip Webb 042 */ 043public abstract class ResourceUtils { 044 045 /** 046 * Pseudo URL prefix for loading from the class path: "classpath:". 047 */ 048 public static final String CLASSPATH_URL_PREFIX = "classpath:"; 049 050 /** 051 * Pseudo URL prefix for loading all resources from the class path: "classpath*:". 052 */ 053 public static final String ALL_CLASSPATH_URL_PREFIX = "classpath*:"; 054 055 /** 056 * URL prefix for loading from the file system: "file:". 057 */ 058 public static final String FILE_URL_PREFIX = "file:"; 059 060 /** 061 * Return URLs from a given source path. Source paths can be simple file locations 062 * (/some/file.java) or wildcard patterns (/some/**). Additionally the prefixes 063 * "file:", "classpath:" and "classpath*:" can be used for specific path types. 064 * @param path the source path 065 * @param classLoader the class loader or {@code null} to use the default 066 * @return a list of URLs 067 */ 068 public static List<String> getUrls(String path, ClassLoader classLoader) { 069 if (classLoader == null) { 070 classLoader = ClassUtils.getDefaultClassLoader(); 071 } 072 path = StringUtils.cleanPath(path); 073 try { 074 return getUrlsFromWildcardPath(path, classLoader); 075 } 076 catch (Exception ex) { 077 throw new IllegalArgumentException( 078 "Cannot create URL from path [" + path + "]", ex); 079 } 080 } 081 082 private static List<String> getUrlsFromWildcardPath(String path, 083 ClassLoader classLoader) throws IOException { 084 if (path.contains(":")) { 085 return getUrlsFromPrefixedWildcardPath(path, classLoader); 086 } 087 Set<String> result = new LinkedHashSet<String>(); 088 try { 089 result.addAll(getUrls(FILE_URL_PREFIX + path, classLoader)); 090 } 091 catch (IllegalArgumentException ex) { 092 // ignore 093 } 094 path = stripLeadingSlashes(path); 095 result.addAll(getUrls(ALL_CLASSPATH_URL_PREFIX + path, classLoader)); 096 return new ArrayList<String>(result); 097 } 098 099 private static List<String> getUrlsFromPrefixedWildcardPath(String path, 100 ClassLoader classLoader) throws IOException { 101 Resource[] resources = new PathMatchingResourcePatternResolver( 102 new FileSearchResourceLoader(classLoader)).getResources(path); 103 List<String> result = new ArrayList<String>(); 104 for (Resource resource : resources) { 105 if (resource.exists()) { 106 if (resource.getURI().getScheme().equals("file")) { 107 if (resource.getFile().isDirectory()) { 108 result.addAll(getChildFiles(resource)); 109 continue; 110 } 111 } 112 result.add(absolutePath(resource)); 113 } 114 } 115 return result; 116 } 117 118 private static List<String> getChildFiles(Resource resource) throws IOException { 119 Resource[] children = new PathMatchingResourcePatternResolver() 120 .getResources(resource.getURL() + "/**"); 121 List<String> childFiles = new ArrayList<String>(); 122 for (Resource child : children) { 123 if (!child.getFile().isDirectory()) { 124 childFiles.add(absolutePath(child)); 125 } 126 } 127 return childFiles; 128 } 129 130 private static String absolutePath(Resource resource) throws IOException { 131 if (!resource.getURI().getScheme().equals("file")) { 132 return resource.getURL().toExternalForm(); 133 } 134 return resource.getFile().getAbsoluteFile().toURI().toString(); 135 } 136 137 private static String stripLeadingSlashes(String path) { 138 while (path.startsWith("/")) { 139 path = path.substring(1); 140 } 141 return path; 142 } 143 144 private static class FileSearchResourceLoader extends DefaultResourceLoader { 145 146 private final FileSystemResourceLoader files; 147 148 FileSearchResourceLoader(ClassLoader classLoader) { 149 super(classLoader); 150 this.files = new FileSystemResourceLoader(); 151 } 152 153 @Override 154 public Resource getResource(String location) { 155 Assert.notNull(location, "Location must not be null"); 156 if (location.startsWith(CLASSPATH_URL_PREFIX)) { 157 return new ClassPathResource( 158 location.substring(CLASSPATH_URL_PREFIX.length()), 159 getClassLoader()); 160 } 161 else { 162 if (location.startsWith(FILE_URL_PREFIX)) { 163 Resource resource = this.files.getResource(location); 164 return resource; 165 } 166 try { 167 // Try to parse the location as a URL... 168 URL url = new URL(location); 169 return new UrlResource(url); 170 } 171 catch (MalformedURLException ex) { 172 // No URL -> resolve as resource path. 173 return getResourceByPath(location); 174 } 175 } 176 } 177 178 } 179 180}