Last active
December 14, 2015 18:39
-
-
Save danieldietrich/5130596 to your computer and use it in GitHub Desktop.
Classpath Resources
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.danieldietrich; | |
import java.io.File; | |
import java.net.URI; | |
import java.net.URL; | |
import java.util.Collections; | |
import java.util.regex.Pattern; | |
import java.util.zip.ZipEntry; | |
import java.util.zip.ZipFile; | |
/** | |
* Based on the Java classpath specification | |
* | |
* http://docs.oracle.com/javase/1.5.0/docs/tooldocs/solaris/classpath.html | |
* http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/classpath.html | |
* | |
* the classpath is scanned for resources, which match a given regex pattern. | |
* | |
* Results are passed to a Visitor. | |
* | |
* @author Daniel Dietrich | |
*/ | |
public class Classpath { | |
private final Pattern pattern; | |
public Classpath(final Pattern pattern) { | |
this.pattern = pattern; | |
} | |
public void getResources(final Visitor visitor) throws Exception { | |
final String classpath = System.getProperty("java.class.path", "."); | |
final String[] classpathElements = classpath.split(File.pathSeparator); | |
for (final String element : classpathElements) { | |
getResources(element, visitor); | |
} | |
} | |
private void getResources(final String element, final Visitor visitor) throws Exception { | |
final File file = new File(element); | |
if (file.isDirectory()) { | |
getResourcesFromDirectory("", file, visitor); | |
} else if (isJarOrZip(file)) { | |
getResourcesFromJarFile(file, visitor); | |
} else { | |
// TODO: LOGGER.info("Ignoring classpath element {}. It is no directory and not a jar/zip file.", element); | |
} | |
} | |
private void getResourcesFromJarFile(final File file, final Visitor visitor) throws Exception { | |
final ZipFile zipFile = new ZipFile(file); | |
for(final ZipEntry zipEntry : Collections.list(zipFile.entries())) { | |
if(!zipEntry.isDirectory()) { | |
final String resource = zipEntry.getName(); | |
final boolean accept = pattern.matcher(resource).matches(); | |
if(accept) { | |
final String path = file.getCanonicalPath().replaceAll("\\\\", "/"); | |
final String escaped = "jar:file:" + escape(path) + "!/" + escape(resource); | |
final URL url = new URI(escaped).toURL(); | |
visitor.visit(resource, url); | |
} | |
} | |
} | |
zipFile.close(); | |
} | |
private void getResourcesFromDirectory(final String path, final File directory, | |
final Visitor visitor) throws Exception { | |
final File[] fileList = directory.listFiles(); | |
for(final File file : fileList) { | |
if(file.isDirectory()) { | |
getResourcesFromDirectory(path + file.getName() + "/", file, visitor); | |
} else { | |
final String fileName = file.getCanonicalPath(); | |
final boolean accept = pattern.matcher(fileName).matches(); | |
if(accept) { | |
final URL url = file.toURI().toURL(); | |
visitor.visit(path + file.getName(), url); | |
} | |
} | |
} | |
} | |
private boolean isJarOrZip(final File file) { | |
// TODO(nice2have): ensure that file content is zip | |
final String name = file.getName().toLowerCase(); | |
return name.endsWith(".jar") || name.endsWith(".zip"); | |
} | |
private String escape(final String s) { | |
// TODO(nice2have): escape all characters accordingly to RFC 2396 | |
return s.replaceAll(" ", "%20"); | |
} | |
public static interface Visitor { | |
void visit(String resource, URL url) throws Exception; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.danieldietrich; | |
import java.net.URL; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.regex.Pattern; | |
/** | |
* Search the classpath for resources which match a specific pattern. | |
* | |
* Arguments: | |
* -Dpattern=<search pattern> (optional, default: .*) | |
* -Dregex=[true|false] (optional, default: false) | |
* | |
* Example: | |
* -Dpattern=*\xml\*.xsd | |
* is the same as | |
* -Dpattern=.*\\xml\\.*\.xsd -Dregex=true | |
* | |
* @author Daniel Dietrich | |
*/ | |
public class Main { | |
public void run(final Pattern pattern) throws Exception { | |
new Classpath(pattern).getResources( | |
new Classpath.Visitor() { | |
private Map<String, URL> visited = new HashMap<String, URL>(); | |
@Override | |
public void visit(final String resource, final URL url) throws Exception { | |
if (!visited.containsKey(resource)) { | |
visited.put(resource, url); | |
/*DELME*/System.out.println("found " + resource + " (" + url + ")"); | |
// TODO: LOGGER.info("found {} ({})", resource, url); | |
// TODO: copy resource to a specific place via url.openStream() | |
} else { | |
/*DELME*/System.out.println("skipping " + resource + " (" + url + " overwritten by " + visited.get(resource) + ")"); | |
// TODO: LOGGER.info("skipping {} ({} overwritten by {})", resource, url, visited.get(resource)); | |
} | |
} | |
} | |
); | |
} | |
public static void main(final String[] args) throws Exception { | |
new Main().run(getPattern()); | |
} | |
private static Pattern getPattern() { | |
final String arg = System.getProperty("pattern"); | |
if (arg == null) { | |
return Pattern.compile(".*"); | |
} else { | |
final boolean isRegex = Boolean.getBoolean("regex"); | |
final String pattern = isRegex ? arg : arg | |
// escape escape-character | |
.replaceAll("\\\\", "\\\\\\\\") | |
// escape wildcard-character | |
.replaceAll("\\.", "\\\\.") | |
// substitute asterisk '*' with wildcard-character '.*' | |
.replaceAll("\\*", ".*"); | |
return Pattern.compile(pattern); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment