1 16 17 package org.springframework.core.io.support; 18 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.net.JarURLConnection ; 22 import java.net.URL ; 23 import java.net.URLConnection ; 24 import java.util.Collections ; 25 import java.util.Enumeration ; 26 import java.util.Iterator ; 27 import java.util.Set ; 28 import java.util.jar.JarEntry ; 29 import java.util.jar.JarFile ; 30 31 import org.apache.commons.logging.Log; 32 import org.apache.commons.logging.LogFactory; 33 34 import org.springframework.core.CollectionFactory; 35 import org.springframework.core.io.DefaultResourceLoader; 36 import org.springframework.core.io.FileSystemResource; 37 import org.springframework.core.io.Resource; 38 import org.springframework.core.io.ResourceLoader; 39 import org.springframework.core.io.UrlResource; 40 import org.springframework.util.AntPathMatcher; 41 import org.springframework.util.Assert; 42 import org.springframework.util.PathMatcher; 43 import org.springframework.util.ResourceUtils; 44 import org.springframework.util.StringUtils; 45 46 159 public class PathMatchingResourcePatternResolver implements ResourcePatternResolver { 160 161 protected final Log logger = LogFactory.getLog(getClass()); 162 163 private final ResourceLoader resourceLoader; 164 165 private PathMatcher pathMatcher = new AntPathMatcher(); 166 167 168 173 public PathMatchingResourcePatternResolver() { 174 this.resourceLoader = new DefaultResourceLoader(); 175 } 176 177 183 public PathMatchingResourcePatternResolver(ClassLoader classLoader) { 184 this.resourceLoader = new DefaultResourceLoader(classLoader); 185 } 186 187 193 public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { 194 Assert.notNull(resourceLoader, "ResourceLoader must not be null"); 195 this.resourceLoader = resourceLoader; 196 } 197 198 199 202 public ResourceLoader getResourceLoader() { 203 return this.resourceLoader; 204 } 205 206 210 public ClassLoader getClassLoader() { 211 return getResourceLoader().getClassLoader(); 212 } 213 214 219 public void setPathMatcher(PathMatcher pathMatcher) { 220 Assert.notNull(pathMatcher, "PathMatcher must not be null"); 221 this.pathMatcher = pathMatcher; 222 } 223 224 227 public PathMatcher getPathMatcher() { 228 return this.pathMatcher; 229 } 230 231 232 public Resource getResource(String location) { 233 return getResourceLoader().getResource(location); 234 } 235 236 public Resource[] getResources(String locationPattern) throws IOException { 237 Assert.notNull(locationPattern, "Location pattern must not be null"); 238 if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { 239 if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { 241 return findPathMatchingResources(locationPattern); 243 } 244 else { 245 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); 247 } 248 } 249 else { 250 int prefixEnd = locationPattern.indexOf(":") + 1; 253 if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { 254 return findPathMatchingResources(locationPattern); 256 } 257 else { 258 return new Resource[] {getResourceLoader().getResource(locationPattern)}; 260 } 261 } 262 } 263 264 265 273 protected Resource[] findAllClassPathResources(String location) throws IOException { 274 String path = location; 275 if (path.startsWith("/")) { 276 path = path.substring(1); 277 } 278 Enumeration resourceUrls = getClassLoader().getResources(path); 279 Set result = CollectionFactory.createLinkedSetIfPossible(16); 280 while (resourceUrls.hasMoreElements()) { 281 URL url = (URL ) resourceUrls.nextElement(); 282 result.add(convertClassLoaderURL(url)); 283 } 284 return (Resource[]) result.toArray(new Resource[result.size()]); 285 } 286 287 295 protected Resource convertClassLoaderURL(URL url) { 296 return new UrlResource(url); 297 } 298 299 310 protected Resource[] findPathMatchingResources(String locationPattern) throws IOException { 311 String rootDirPath = determineRootDir(locationPattern); 312 String subPattern = locationPattern.substring(rootDirPath.length()); 313 Resource[] rootDirResources = getResources(rootDirPath); 314 Set result = CollectionFactory.createLinkedSetIfPossible(16); 315 for (int i = 0; i < rootDirResources.length; i++) { 316 Resource rootDirResource = rootDirResources[i]; 317 if (isJarResource(rootDirResource)) { 318 result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); 319 } 320 else { 321 result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); 322 } 323 } 324 if (logger.isDebugEnabled()) { 325 logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result); 326 } 327 return (Resource[]) result.toArray(new Resource[result.size()]); 328 } 329 330 342 protected String determineRootDir(String location) { 343 int prefixEnd = location.indexOf(":") + 1; 344 int rootDirEnd = location.length(); 345 while (rootDirEnd > prefixEnd && getPathMatcher().isPattern(location.substring(prefixEnd, rootDirEnd))) { 346 rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1; 347 } 348 if (rootDirEnd == 0) { 349 rootDirEnd = prefixEnd; 350 } 351 return location.substring(0, rootDirEnd); 352 } 353 354 365 protected boolean isJarResource(Resource resource) throws IOException { 366 return ResourceUtils.isJarURL(resource.getURL()); 367 } 368 369 379 protected Set doFindPathMatchingJarResources(Resource rootDirResource, String subPattern) throws IOException { 380 URLConnection con = rootDirResource.getURL().openConnection(); 381 JarFile jarFile = null; 382 String jarFileUrl = null; 383 String rootEntryPath = null; 384 385 if (con instanceof JarURLConnection ) { 386 JarURLConnection jarCon = (JarURLConnection ) con; 388 jarFile = jarCon.getJarFile(); 389 jarFileUrl = jarCon.getJarFileURL().toExternalForm(); 390 JarEntry jarEntry = jarCon.getJarEntry(); 391 rootEntryPath = (jarEntry != null ? jarEntry.getName() : ""); 392 } 393 else { 394 String urlFile = rootDirResource.getURL().getFile(); 399 int separatorIndex = urlFile.indexOf(ResourceUtils.JAR_URL_SEPARATOR); 400 jarFileUrl = urlFile.substring(0, separatorIndex); 401 if (jarFileUrl.startsWith(ResourceUtils.FILE_URL_PREFIX)) { 402 jarFileUrl = jarFileUrl.substring(ResourceUtils.FILE_URL_PREFIX.length()); 403 } 404 jarFile = new JarFile (jarFileUrl); 405 jarFileUrl = ResourceUtils.FILE_URL_PREFIX + jarFileUrl; 406 rootEntryPath = urlFile.substring(separatorIndex + ResourceUtils.JAR_URL_SEPARATOR.length()); 407 } 408 409 if (logger.isDebugEnabled()) { 410 logger.debug("Looking for matching resources in jar file [" + jarFileUrl + "]"); 411 } 412 if (!"".equals(rootEntryPath) && !rootEntryPath.endsWith("/")) { 413 rootEntryPath = rootEntryPath + "/"; 416 } 417 Set result = CollectionFactory.createLinkedSetIfPossible(8); 418 for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { 419 JarEntry entry = (JarEntry ) entries.nextElement(); 420 String entryPath = entry.getName(); 421 if (entryPath.startsWith(rootEntryPath)) { 422 String relativePath = entryPath.substring(rootEntryPath.length()); 423 if (getPathMatcher().match(subPattern, relativePath)) { 424 result.add(rootDirResource.createRelative(relativePath)); 425 } 426 } 427 } 428 return result; 429 } 430 431 441 protected Set doFindPathMatchingFileResources(Resource rootDirResource, String subPattern) throws IOException { 442 File rootDir = null; 443 try { 444 rootDir = rootDirResource.getFile().getAbsoluteFile(); 445 } 446 catch (IOException ex) { 447 if (logger.isDebugEnabled()) { 448 logger.debug("Cannot search for matching files underneath " + rootDirResource + 449 " because it does not correspond to a directory in the file system", ex); 450 } 451 return Collections.EMPTY_SET; 452 } 453 return doFindMatchingFileSystemResources(rootDir, subPattern); 454 } 455 456 466 protected Set doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException { 467 if (logger.isDebugEnabled()) { 468 logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]"); 469 } 470 Set matchingFiles = retrieveMatchingFiles(rootDir, subPattern); 471 Set result = CollectionFactory.createLinkedSetIfPossible(matchingFiles.size()); 472 for (Iterator it = matchingFiles.iterator(); it.hasNext();) { 473 File file = (File ) it.next(); 474 result.add(new FileSystemResource(file)); 475 } 476 return result; 477 } 478 479 488 protected Set retrieveMatchingFiles(File rootDir, String pattern) throws IOException { 489 if (!rootDir.isDirectory()) { 490 throw new IllegalArgumentException ("Resource path [" + rootDir + "] does not denote a directory"); 491 } 492 String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/"); 493 if (!pattern.startsWith("/")) { 494 fullPattern += "/"; 495 } 496 fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/"); 497 Set result = CollectionFactory.createLinkedSetIfPossible(8); 498 doRetrieveMatchingFiles(fullPattern, rootDir, result); 499 return result; 500 } 501 502 511 protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set result) throws IOException { 512 if (logger.isDebugEnabled()) { 513 logger.debug("Searching directory [" + dir.getAbsolutePath() + 514 "] for files matching pattern [" + fullPattern + "]"); 515 } 516 File [] dirContents = dir.listFiles(); 517 if (dirContents == null) { 518 throw new IOException ("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]"); 519 } 520 boolean dirDepthNotFixed = (fullPattern.indexOf("**") != -1); 521 for (int i = 0; i < dirContents.length; i++) { 522 String currPath = StringUtils.replace(dirContents[i].getAbsolutePath(), File.separator, "/"); 523 if (dirContents[i].isDirectory() && 524 (dirDepthNotFixed || 525 StringUtils.countOccurrencesOf(currPath, "/") < StringUtils.countOccurrencesOf(fullPattern, "/"))) { 526 doRetrieveMatchingFiles(fullPattern, dirContents[i], result); 527 } 528 if (getPathMatcher().match(fullPattern, currPath)) { 529 result.add(dirContents[i]); 530 } 531 } 532 } 533 534 } 535 | Popular Tags |