Merge pull request #89 from dscho/get-resources

Support ClassLoader#getResources with multiple class path elements
This commit is contained in:
Joshua Warner 2013-11-04 16:29:40 -08:00
commit 790fcff73e
7 changed files with 111 additions and 13 deletions

View File

@ -17,6 +17,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.NoSuchElementException;
public class SystemClassLoader extends ClassLoader { public class SystemClassLoader extends ClassLoader {
private native VMClass findVMClass(String name) private native VMClass findVMClass(String name)
@ -106,20 +107,51 @@ public class SystemClassLoader extends ClassLoader {
} }
} }
URL url = findResource(name); Enumeration<URL> urls2 = findResources(name);
if (url != null) { while (urls2.hasMoreElements()) {
urls.add(url); urls.add(urls2.nextElement());
} }
return Collections.enumeration(urls); return Collections.enumeration(urls);
} }
private class ResourceEnumeration implements Enumeration<URL> {
private long[] finderElementPtrPtr;
private String name, urlPrefix;
public ResourceEnumeration(String name) {
this.name = name;
finderElementPtrPtr = new long[1];
urlPrefix = nextResourceURLPrefix();
}
private native String nextResourceURLPrefix(SystemClassLoader loader,
String name, long[] finderElementPtrPtr);
private String nextResourceURLPrefix() {
return nextResourceURLPrefix(SystemClassLoader.this, name,
finderElementPtrPtr);
}
public boolean hasMoreElements() {
return urlPrefix != null;
}
public URL nextElement() {
if (urlPrefix == null) throw new NoSuchElementException();
URL result;
try {
result = new URL(urlPrefix + name);
} catch (MalformedURLException ignored) {
result = null;
}
if (finderElementPtrPtr[0] == 0l) urlPrefix = null;
else urlPrefix = nextResourceURLPrefix();
return result;
}
}
protected Enumeration<URL> findResources(String name) { protected Enumeration<URL> findResources(String name) {
Collection<URL> urls = new ArrayList(1); return new ResourceEnumeration(name);
URL url = findResource(name);
if (url != null) {
urls.add(url);
}
return Collections.enumeration(urls);
} }
} }

View File

@ -42,7 +42,7 @@ public class Handler extends URLStreamHandler {
("protocol " + file.getProtocol() + " not yet supported"); ("protocol " + file.getProtocol() + " not yet supported");
} }
url.set("jar", "", -1, s, null); url.set("jar", null, -1, s, null);
} }
private static class MyJarURLConnection extends JarURLConnection { private static class MyJarURLConnection extends JarURLConnection {

View File

@ -1487,13 +1487,20 @@ ifeq ($(continuations),true)
$(build)/compile-x86-asm.o: $(src)/continuations-x86.$(asm-format) $(build)/compile-x86-asm.o: $(src)/continuations-x86.$(asm-format)
endif endif
$(build)/run-tests.sh: $(test-classes) makefile $(build)/run-tests.sh: $(test-classes) makefile $(build)/extra-dir/multi-classpath-test.txt $(build)/test/multi-classpath-test.txt
echo 'cd $$(dirname $$0)' > $(@) echo 'cd $$(dirname $$0)' > $(@)
echo "sh ./test.sh 2>/dev/null \\" >> $(@) echo "sh ./test.sh 2>/dev/null \\" >> $(@)
echo "$(shell echo $(library-path) | sed 's|$(build)|\.|g') ./$(name)-unittest${exe-suffix} ./$(notdir $(test-executable)) $(mode) \"-Djava.library.path=. -cp test\" \\" >> $(@) echo "$(shell echo $(library-path) | sed 's|$(build)|\.|g') ./$(name)-unittest${exe-suffix} ./$(notdir $(test-executable)) $(mode) \"-Djava.library.path=. -cp test:extra-dir\" \\" >> $(@)
echo "$(call class-names,$(test-build),$(filter-out $(test-support-classes), $(test-classes))) \\" >> $(@) echo "$(call class-names,$(test-build),$(filter-out $(test-support-classes), $(test-classes))) \\" >> $(@)
echo "$(continuation-tests) $(tail-tests)" >> $(@) echo "$(continuation-tests) $(tail-tests)" >> $(@)
$(build)/extra-dir/multi-classpath-test.txt:
mkdir -p $(build)/extra-dir
echo "$@" > $@
$(build)/test/multi-classpath-test.txt:
echo "$@" > $@
$(build)/test.sh: $(test)/test.sh $(build)/test.sh: $(test)/test.sh
cp $(<) $(@) cp $(<) $(@)

View File

@ -168,6 +168,7 @@ class Finder {
unsigned* length, unsigned* length,
bool tryDirectory = false) = 0; bool tryDirectory = false) = 0;
virtual const char* urlPrefix(const char* name) = 0; virtual const char* urlPrefix(const char* name) = 0;
virtual const char* nextUrlPrefix(const char* name, void *&finderElementPtr) = 0;
virtual const char* sourceUrl(const char* name) = 0; virtual const char* sourceUrl(const char* name) = 0;
virtual const char* path() = 0; virtual const char* path() = 0;
virtual void dispose() = 0; virtual void dispose() = 0;

View File

@ -152,6 +152,30 @@ Avian_avian_SystemClassLoader_resourceURLPrefix
} }
} }
extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_00024ResourceEnumeration_nextResourceURLPrefix
(Thread* t, object, uintptr_t* arguments)
{
object loader = reinterpret_cast<object>(arguments[1]);
object name = reinterpret_cast<object>(arguments[2]);
object finderElementPtrPtr = reinterpret_cast<object>(arguments[3]);
if (LIKELY(name) && LIKELY(finderElementPtrPtr)) {
THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1);
stringChars(t, name, RUNTIME_ARRAY_BODY(n));
void *&finderElementPtr = reinterpret_cast<void *&>(longArrayBody(t,
finderElementPtrPtr, 0));
const char* name = static_cast<Finder*>
(systemClassLoaderFinder(t, loader))->nextUrlPrefix(RUNTIME_ARRAY_BODY(n),
finderElementPtr);
return name ? reinterpret_cast<uintptr_t>(makeString(t, "%s", name)) : 0;
} else {
throwNew(t, Machine::NullPointerExceptionType);
}
}
extern "C" JNIEXPORT int64_t JNICALL extern "C" JNIEXPORT int64_t JNICALL
Avian_avian_SystemClassLoader_getClass Avian_avian_SystemClassLoader_getClass
(Thread* t, object, uintptr_t* arguments) (Thread* t, object, uintptr_t* arguments)

View File

@ -908,7 +908,16 @@ class MyFinder: public Finder {
} }
virtual const char* urlPrefix(const char* name) { virtual const char* urlPrefix(const char* name) {
for (Element* e = path_; e; e = e->next) { void *finderElementPtr = NULL;
return nextUrlPrefix(name, finderElementPtr);
}
virtual const char* nextUrlPrefix(const char* name,
void *&finderElementPtr)
{
Element *&e = reinterpret_cast<Element*&>(finderElementPtr);
e = e ? e->next : path_;
for (; e; e = e->next) {
unsigned length; unsigned length;
System::FileType type = e->stat(name, &length, true); System::FileType type = e->stat(name, &length, true);
if (type != System::TypeDoesNotExist) { if (type != System::TypeDoesNotExist) {

View File

@ -1,3 +1,7 @@
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
public class Misc { public class Misc {
private static class μClass { private static class μClass {
public int μField; public int μField;
@ -262,6 +266,27 @@ public class Misc {
expect((Protected.class.getModifiers() & java.lang.reflect.Modifier.PUBLIC) expect((Protected.class.getModifiers() & java.lang.reflect.Modifier.PUBLIC)
== 0); == 0);
try {
int count = 0;
boolean test = false, extraDir = false;
ClassLoader loader = Misc.class.getClassLoader();
Enumeration<URL> resources = loader.getResources("multi-classpath-test.txt");
while (resources.hasMoreElements()) {
++count;
String url = resources.nextElement().toString();
if (url.contains("extra-dir")) {
extraDir = true;
} else if (url.contains("test")) {
test = true;
}
}
expect(count == 2);
expect(test);
expect(extraDir);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
protected class Protected { } protected class Protected { }