001/* 002 * Copyright 2012 Chris Pheby 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 */ 016package org.jadira.scanner.file.locator; 017 018import java.io.File; 019import java.io.IOException; 020import java.io.UnsupportedEncodingException; 021import java.net.MalformedURLException; 022import java.net.URL; 023import java.net.URLDecoder; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.jadira.scanner.core.api.Locator; 028import org.jadira.scanner.core.exception.FileAccessException; 029import org.jadira.scanner.core.utils.lang.IterableEnumeration; 030import org.jadira.scanner.core.utils.reflection.ClassLoaderUtils; 031 032/** 033 * Matches any Jars with a marker file indicated 034 */ 035public class PackagesClasspathUrlLocator implements Locator<URL> { 036 037 private List<String> paths; 038 039 private final ClassLoader[] classLoaders; 040 041 public PackagesClasspathUrlLocator(String markerFilePath, ClassLoader... classLoaders) { 042 this.paths = new ArrayList<String>(1); 043 paths.add(asNormalizedName(markerFilePath)); 044 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders); 045 } 046 047 public PackagesClasspathUrlLocator(List<String> markerFilePaths, ClassLoader... classLoaders) { 048 this.paths = new ArrayList<String>(markerFilePaths.size()); 049 for (String next : markerFilePaths) { 050 paths.add(asNormalizedName(next)); 051 } 052 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders); 053 } 054 055 @Override 056 public List<URL> locate() { 057 058 List<URL> list = new ArrayList<URL>(); 059 060 for (ClassLoader classLoader : classLoaders) { 061 try { 062 for (String nextPath : paths) { 063 for (URL nextResourceMatchedUrl : new IterableEnumeration<URL>(classLoader.getResources(nextPath))) { 064 065 String deploymentArchiveRoot = determineClasspathRootForResource(nextPath, nextResourceMatchedUrl); 066 067 File fp = new File(deploymentArchiveRoot); 068 069 if (!fp.exists()) { 070 throw new FileAccessException("File unexpectedly does not exist: " + fp); 071 } 072 073 try { 074 list.add(fp.toURI().toURL()); 075 } catch (MalformedURLException e) { 076 throw new FileAccessException("Filepath unexpectedly malformed: " + fp.getPath(), e); 077 } 078 } 079 } 080 } catch (IOException e) { 081 throw new FileAccessException("Problem resolving deployment archives: " + e.getMessage(), e); 082 } 083 } 084 085 return list; 086 } 087 088 private String determineClasspathRootForResource(String nextResource, URL nextResourceMatchedUrl) { 089 090 String nextResourceMatchedPathName = nextResourceMatchedUrl.getFile(); 091 try { 092 nextResourceMatchedPathName = URLDecoder.decode(nextResourceMatchedPathName, "UTF-8"); 093 } catch (UnsupportedEncodingException e) { 094 // Never thrown for UTF-8 095 throw new FileAccessException("Exception thrown for Encoding when not expected: " + e.getMessage(), e); 096 } 097 098 // Reformat file urls to remove file: prefix 099 if (nextResourceMatchedPathName.startsWith("file:")) { 100 nextResourceMatchedPathName = nextResourceMatchedPathName.substring(5); 101 } 102 103 // Chomp archive name if an archive 104 if (nextResourceMatchedPathName.indexOf('!') > 0) { 105 nextResourceMatchedPathName = nextResourceMatchedPathName.substring(0, nextResourceMatchedPathName.indexOf('!')); 106 } else { 107 File indicatedResource = new File(nextResourceMatchedPathName); 108 109 // Traverse to classpath root relative to the original matching resource 110 int pathDepth = nextResource.replaceAll("[^/]", "").length(); 111 for (int i = 0; i < pathDepth; i++) { 112 indicatedResource = indicatedResource.getParentFile(); 113 } 114 nextResourceMatchedPathName = indicatedResource.getParent(); 115 } 116 117 return nextResourceMatchedPathName; 118 } 119 120 private static String asNormalizedName(String name) { 121 122 String result = name; 123 if (result != null) { 124 result = result.replace(".", "/"); 125 result = result.replace("\\", "/"); 126 if (result.startsWith("/")) { 127 result = result.substring(1); 128 } 129 } 130 return result; 131 } 132}