/**
* Copyright 2010 Marko Lavikainen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.contextfw.web.application.internal.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import net.contextfw.web.application.WebApplicationException;
/**
* Locates all resources with given extension from paths
*
* @author marko
*
*/
public abstract class AbstractScanner {
private static final String FILE = "file";
private static final String CLASSPATH = "classpath";
protected AbstractScanner() {
}
protected static List<ResourceEntry> findResourceEntries(List<String> resourcePaths) {
List<ResourceEntry> entries = new ArrayList<ResourceEntry>();
List<URI> rootURIs = toURIs(resourcePaths);
try {
for (URI rootURI : rootURIs) {
if (FILE.equals(rootURI.getScheme())) {
entries.addAll(findResourcesFromFilesystem(rootURI));
} else if (CLASSPATH.equals(rootURI.getScheme())) {
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader()
.getResources(rootURI.getSchemeSpecificPart());
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
if ("file".equals(resource.getProtocol())) {
entries.addAll(findResourcesFromFilesystem(rootURI.getSchemeSpecificPart(), resource));
} else if ("jar".equals(resource.getProtocol())) {
entries.addAll(findResourcesFromJar(resource));
} else {
throw new WebApplicationException("Protocol " + resource.getProtocol() + " is not supported");
}
}
}
}
} catch (IOException e) {
throw new WebApplicationException(e);
} catch (URISyntaxException e) {
throw new WebApplicationException(e);
}
return entries;
}
private static Collection<? extends ResourceEntry> findResourcesFromJar(URL directory) throws IOException {
List<ResourceEntry> resources = new ArrayList<ResourceEntry>();
String jarPath = directory.getPath().substring(5, directory.getPath().indexOf("!"));
String path = directory.getPath().substring(directory.getPath().indexOf("!") + 2);
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries();
while(entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().startsWith(path) && !entry.isDirectory()) {
resources.add(new JarResourceEntry(jar, entry));
}
}
return resources;
}
private static Collection<? extends ResourceEntry> findResourcesFromFilesystem(String pathPrefix, URL rootUrl) throws URISyntaxException, FileNotFoundException, UnsupportedEncodingException {
File rootDirectory = new File(URLDecoder.decode(rootUrl.getFile(), "UTF-8"));
if (rootDirectory.isDirectory()) {
return findResourcesFromFilesystem(pathPrefix+"/", rootDirectory);
} else {
return Collections.emptyList();
}
}
private static Collection<? extends ResourceEntry> findResourcesFromFilesystem(URI rootURI) throws FileNotFoundException {
File rootDirectory = new File(rootURI.getSchemeSpecificPart());
if (!rootDirectory.isDirectory()) {
throw new WebApplicationException("File " + rootDirectory.getAbsolutePath() + " is not a directory");
} else {
return findResourcesFromFilesystem(rootURI.getSchemeSpecificPart()+"/", rootDirectory);
}
}
private static Collection<? extends ResourceEntry> findResourcesFromFilesystem(String pathPrefix, File rootDirectory) throws FileNotFoundException {
List<ResourceEntry> entries = new ArrayList<ResourceEntry>();
if (!rootDirectory.exists()) {
throw new WebApplicationException("Directory " + rootDirectory.getAbsolutePath() + " does not exist");
}
int length = rootDirectory.getPath().length() + 1;
List<File> directories = new ArrayList<File>();
directories.add(rootDirectory);
while (!directories.isEmpty()) {
File dir = directories.remove(0);
for (File child : dir.listFiles()) {
if (child.isDirectory()) {
directories.add(child);
} else {
entries.add(new FileResourceEntry(pathPrefix+child.getPath().substring(length), child));
}
}
}
return entries;
}
public static List<URI> toURIs(Collection<String> resourcePaths) {
List<URI> roots = new ArrayList<URI>(resourcePaths.size());
for (String path : resourcePaths) {
int separator = path.indexOf(":");
try {
if (separator == -1) {
roots.add(new URI("classpath", path.replaceAll("\\.", "/"),
null));
} else {
String scheme = path.substring(0, separator);
String ssp = path.substring(separator+1);
if (!CLASSPATH.equals(scheme) && !FILE.equals(scheme)) {
throw new WebApplicationException("Scheme '" + scheme
+ "' is not supported. Path was: " + path);
}
roots.add(new URI(scheme, ssp, null));
}
} catch (URISyntaxException e) {
throw new WebApplicationException(e);
}
}
return roots;
}
}