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 PackagesClasspathUrlLocator implements Locator<URL> {
36  
37  	private List<String> paths;
38  
39  	private final ClassLoader[] classLoaders;
40  	   
41  	public PackagesClasspathUrlLocator(String markerFilePath, ClassLoader... classLoaders) {
42  		this.paths = new ArrayList<String>(1);
43  		paths.add(asNormalizedName(markerFilePath));
44  		this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
45  	}
46  	
47      public PackagesClasspathUrlLocator(List<String> markerFilePaths, ClassLoader... classLoaders) {
48  		this.paths = new ArrayList<String>(markerFilePaths.size());
49  		for (String next : markerFilePaths) {
50  		    paths.add(asNormalizedName(next));
51  		}
52  		this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
53  	}
54  	
55  	@Override
56  	public List<URL> locate() {
57  
58          List<URL> list = new ArrayList<URL>();
59          
60          for (ClassLoader classLoader : classLoaders) {
61              try {
62              	for (String nextPath : paths) {        	    
63      	            for (URL nextResourceMatchedUrl : new IterableEnumeration<URL>(classLoader.getResources(nextPath))) {
64      	
65      	                String deploymentArchiveRoot = determineClasspathRootForResource(nextPath, nextResourceMatchedUrl);
66      	                
67                          File fp = new File(deploymentArchiveRoot);
68                          
69                          if (!fp.exists()) {
70                              throw new FileAccessException("File unexpectedly does not exist: " + fp);
71                          }
72                          
73                          try {
74                              list.add(fp.toURI().toURL());
75                          } catch (MalformedURLException e) {
76                          	throw new FileAccessException("Filepath unexpectedly malformed: " + fp.getPath(), e);
77                          }
78      	            }
79              	}
80              } catch (IOException e) {
81              	throw new FileAccessException("Problem resolving deployment archives: " + e.getMessage(), e);
82              }
83          }
84  		
85          return list;
86      }
87  	
88      private String determineClasspathRootForResource(String nextResource, URL nextResourceMatchedUrl) {
89  
90          String nextResourceMatchedPathName = nextResourceMatchedUrl.getFile();
91          try {
92              nextResourceMatchedPathName = URLDecoder.decode(nextResourceMatchedPathName, "UTF-8");
93          } catch (UnsupportedEncodingException e) {
94              // Never thrown for UTF-8
95              throw new FileAccessException("Exception thrown for Encoding when not expected: " + e.getMessage(), e);
96          }
97  
98          // Reformat file urls to remove file: prefix
99          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 }