blob: d2210a4ac4dac725a1ce76b220f86fb964531929 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* 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 com.tonicsystems.jarjar.util;
import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;
public class ClassPathIterator implements Iterator<ClassPathEntry> {
private static final FileFilter CLASS_FILTER =
new FileFilter() {
public boolean accept(File file) {
return file.isDirectory() || isClass(file.getName());
}
};
private static final FileFilter JAR_FILTER =
new FileFilter() {
public boolean accept(File file) {
return hasExtension(file.getName(), ".jar");
}
};
private final Iterator<File> files;
private Iterator<ClassPathEntry> entries = Collections.<ClassPathEntry>emptyList().iterator();
private ClassPathEntry next;
private List<ZipFile> zips = new ArrayList<ZipFile>();
public ClassPathIterator(String classPath) throws IOException {
this(new File(System.getProperty("user.dir")), classPath, null);
}
public ClassPathIterator(File parent, String classPath, String delim) throws IOException {
if (delim == null) {
delim = System.getProperty("path.separator");
}
StringTokenizer st = new StringTokenizer(classPath, delim);
List<File> fileList = new ArrayList<File>();
while (st.hasMoreTokens()) {
String part = (String) st.nextElement();
boolean wildcard = false;
if (part.endsWith("/*")) {
part = part.substring(0, part.length() - 1);
if (part.indexOf('*') >= 0) {
throw new IllegalArgumentException("Multiple wildcards are not allowed: " + part);
}
wildcard = true;
} else if (part.indexOf('*') >= 0) {
throw new IllegalArgumentException("Incorrect wildcard usage: " + part);
}
File file = new File(part);
if (!file.isAbsolute()) {
file = new File(parent, part);
}
if (!file.exists()) {
throw new IllegalArgumentException("File " + file + " does not exist");
}
if (wildcard) {
if (!file.isDirectory()) {
throw new IllegalArgumentException("File " + file + " + is not a directory");
}
fileList.addAll(findFiles(file, JAR_FILTER, false, new ArrayList<File>()));
} else {
fileList.add(file);
}
}
this.files = fileList.iterator();
advance();
}
public boolean hasNext() {
return next != null;
}
/** Closes all zip files opened by this iterator. */
public void close() throws IOException {
next = null;
for (ZipFile zip : zips) {
zip.close();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public ClassPathEntry next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
ClassPathEntry result = next;
try {
advance();
} catch (IOException e) {
throw new RuntimeIOException(e);
}
return result;
}
private void advance() throws IOException {
if (!entries.hasNext()) {
if (!files.hasNext()) {
next = null;
return;
}
File file = files.next();
if (hasExtension(file.getName(), ".jar")) {
ZipFile zip = new JarFile(file);
zips.add(zip);
entries = new ZipIterator(zip);
} else if (hasExtension(file.getName(), ".zip")) {
ZipFile zip = new ZipFile(file);
zips.add(zip);
entries = new ZipIterator(zip);
} else if (file.isDirectory()) {
entries = new FileIterator(file);
} else {
throw new IllegalArgumentException("Do not know how to handle " + file);
}
}
boolean foundClass = false;
while (!foundClass && entries.hasNext()) {
next = entries.next();
foundClass = isClass(next.getName());
}
if (!foundClass) {
advance();
}
}
private static class ZipIterator implements Iterator<ClassPathEntry> {
private final ZipFile zip;
private final Enumeration<? extends ZipEntry> entries;
ZipIterator(ZipFile zip) {
this.zip = zip;
this.entries = zip.entries();
}
public boolean hasNext() {
return entries.hasMoreElements();
}
public void remove() {
throw new UnsupportedOperationException();
}
public ClassPathEntry next() {
final ZipEntry entry = entries.nextElement();
return new ClassPathEntry() {
public String getSource() {
return zip.getName();
}
public String getName() {
return entry.getName();
}
public InputStream openStream() throws IOException {
return zip.getInputStream(entry);
}
};
}
}
private static class FileIterator implements Iterator<ClassPathEntry> {
private final File dir;
private final Iterator<File> entries;
FileIterator(File dir) {
this.dir = dir;
this.entries = findFiles(dir, CLASS_FILTER, true, new ArrayList<File>()).iterator();
}
public boolean hasNext() {
return entries.hasNext();
}
public void remove() {
throw new UnsupportedOperationException();
}
public ClassPathEntry next() {
final File file = entries.next();
return new ClassPathEntry() {
public String getSource() throws IOException {
return dir.getCanonicalPath();
}
public String getName() {
return file.getName();
}
public InputStream openStream() throws IOException {
return new BufferedInputStream(new FileInputStream(file));
}
};
}
}
private static List<File> findFiles(
File dir, FileFilter filter, boolean recurse, List<File> collect) {
for (File file : dir.listFiles(filter)) {
if (recurse && file.isDirectory()) {
findFiles(file, filter, recurse, collect);
} else {
collect.add(file);
}
}
return collect;
}
private static boolean isClass(String name) {
return hasExtension(name, ".class");
}
private static boolean hasExtension(String name, String ext) {
if (name.length() < ext.length()) {
return false;
}
String actual = name.substring(name.length() - ext.length());
return actual.equals(ext) || actual.equals(ext.toUpperCase());
}
}