View Javadoc
1   /*
2    *  Copyright 2012 Chris Pheby
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.jadira.scanner.file.locator;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.UnsupportedEncodingException;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.net.URLDecoder;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.jadira.scanner.core.api.Locator;
28  import org.jadira.scanner.core.exception.FileAccessException;
29  import org.jadira.scanner.core.utils.lang.IterableEnumeration;
30  import org.jadira.scanner.core.utils.reflection.ClassLoaderUtils;
31  
32  /**
33   * Matches any Jars with a marker file indicated
34   */
35  public class ContainedClassClasspathUrlLocator implements Locator<URL> {
36  
37  	private final List<String> paths;
38  	
39  	private final ClassLoader[] classLoaders;
40  
41  	public ContainedClassClasspathUrlLocator(Class<?> clazz, ClassLoader... classLoaders) {
42  		this.paths = new ArrayList<String>(1);
43  		paths.add(asNormalizedName(clazz));
44  		
45  		this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
46  	}
47  	
48  	public ContainedClassClasspathUrlLocator(List<Class<?>> classes, ClassLoader... classLoaders) {
49          this.paths = new ArrayList<String>(classes.size());
50          for (Class<?> next : classes) {
51              paths.add(asNormalizedName(next));
52          }
53          
54          this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
55  	}
56  	
57  	@Override
58  	public List<URL> locate() {
59  
60          List<URL> list = new ArrayList<URL>();
61          
62          for (ClassLoader classLoader : classLoaders) {
63              try {
64              	for (String nextPath : paths) {
65      	            for (URL nextResourceMatchedUrl : new IterableEnumeration<URL>(classLoader.getResources(nextPath))) {
66      	
67      	                String deploymentArchiveRoot = determineClasspathRootForResource(nextPath, nextResourceMatchedUrl);
68      	                
69                          File fp = new File(deploymentArchiveRoot);
70                          
71                          if (!fp.exists()) {
72                              throw new FileAccessException("File unexpectedly does not exist: " + fp);
73                          }
74                          
75                          try {
76                              list.add(fp.toURI().toURL());
77                          } catch (MalformedURLException e) {
78                          	throw new FileAccessException("Filepath unexpectedly malformed: " + fp.getPath(), e);
79                          }
80      	            }
81              	}
82              } catch (IOException e) {
83              	throw new FileAccessException("Problem resolving deployment archives: " + e.getMessage(), e);
84              }
85          }
86  		
87          return list;
88      }
89  	
90      private String determineClasspathRootForResource(String nextResource, URL nextResourceMatchedUrl) {
91  
92          String nextResourceMatchedPathName = nextResourceMatchedUrl.getFile();
93          try {
94              nextResourceMatchedPathName = URLDecoder.decode(nextResourceMatchedPathName, "UTF-8");
95          } catch (UnsupportedEncodingException e) {
96              // Never thrown for UTF-8
97              throw new FileAccessException("Exception thrown for Encoding when not expected: " + e.getMessage(), e);
98          }
99  
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 }