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 ContainedClassClasspathUrlLocator implements Locator<URL> { 036 037 private final List<String> paths; 038 039 private final ClassLoader[] classLoaders; 040 041 public ContainedClassClasspathUrlLocator(Class<?> clazz, ClassLoader... classLoaders) { 042 this.paths = new ArrayList<String>(1); 043 paths.add(asNormalizedName(clazz)); 044 045 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders); 046 } 047 048 public ContainedClassClasspathUrlLocator(List<Class<?>> classes, ClassLoader... classLoaders) { 049 this.paths = new ArrayList<String>(classes.size()); 050 for (Class<?> next : classes) { 051 paths.add(asNormalizedName(next)); 052 } 053 054 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders); 055 } 056 057 @Override 058 public List<URL> locate() { 059 060 List<URL> list = new ArrayList<URL>(); 061 062 for (ClassLoader classLoader : classLoaders) { 063 try { 064 for (String nextPath : paths) { 065 for (URL nextResourceMatchedUrl : new IterableEnumeration<URL>(classLoader.getResources(nextPath))) { 066 067 String deploymentArchiveRoot = determineClasspathRootForResource(nextPath, nextResourceMatchedUrl); 068 069 File fp = new File(deploymentArchiveRoot); 070 071 if (!fp.exists()) { 072 throw new FileAccessException("File unexpectedly does not exist: " + fp); 073 } 074 075 try { 076 list.add(fp.toURI().toURL()); 077 } catch (MalformedURLException e) { 078 throw new FileAccessException("Filepath unexpectedly malformed: " + fp.getPath(), e); 079 } 080 } 081 } 082 } catch (IOException e) { 083 throw new FileAccessException("Problem resolving deployment archives: " + e.getMessage(), e); 084 } 085 } 086 087 return list; 088 } 089 090 private String determineClasspathRootForResource(String nextResource, URL nextResourceMatchedUrl) { 091 092 String nextResourceMatchedPathName = nextResourceMatchedUrl.getFile(); 093 try { 094 nextResourceMatchedPathName = URLDecoder.decode(nextResourceMatchedPathName, "UTF-8"); 095 } catch (UnsupportedEncodingException e) { 096 // Never thrown for UTF-8 097 throw new FileAccessException("Exception thrown for Encoding when not expected: " + e.getMessage(), e); 098 } 099 100 // Reformat file urls to remove file: prefix 101 if (nextResourceMatchedPathName.startsWith("file:")) { 102 nextResourceMatchedPathName = nextResourceMatchedPathName.substring(5); 103 } 104 105 // Chomp archive name if an archive 106 if (nextResourceMatchedPathName.indexOf('!') > 0) { 107 nextResourceMatchedPathName = nextResourceMatchedPathName.substring(0, nextResourceMatchedPathName.indexOf('!')); 108 } else { 109 File indicatedResource = new File(nextResourceMatchedPathName); 110 111 // Traverse to classpath root relative to the original matching resource 112 int pathDepth = nextResource.replaceAll("[^/]", "").length(); 113 for (int i = 0; i < pathDepth; i++) { 114 indicatedResource = indicatedResource.getParentFile(); 115 } 116 nextResourceMatchedPathName = indicatedResource.getParent(); 117 } 118 119 return nextResourceMatchedPathName; 120 } 121 122 123 private static String asNormalizedName(Class<?> clazz) { 124 125 String result = clazz.getName().replace(".", "/") + ".class"; 126 return result; 127 } 128}