diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 06dd0cc375..740d5199c6 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -325,10 +325,10 @@ Java_java_io_File_length(JNIEnv* e, jclass, jstring path) if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); + releaseChars(e, path, chars); if (r == 0) { return s.st_size; } - releaseChars(e, path, chars); } return -1; @@ -624,7 +624,9 @@ Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path, jboolean app { string_t chars = getChars(e, path); if (chars) { - int fd = doOpen(e, chars, append ? (O_WRONLY | O_APPEND) : (O_WRONLY | O_CREAT | O_TRUNC)); + int fd = doOpen(e, chars, append + ? (O_WRONLY | O_CREAT | O_APPEND) + : (O_WRONLY | O_CREAT | O_TRUNC)); releaseChars(e, path, chars); return fd; } else { diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 2e5d37bb1a..9a7656db91 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -279,7 +279,7 @@ doListen(JNIEnv* e, int s, sockaddr_in* address) } } -bool +void doFinishConnect(JNIEnv* e, int socket) { int error; @@ -289,12 +289,9 @@ doFinishConnect(JNIEnv* e, int socket) if (r != 0 or size != sizeof(int)) { throwIOException(e); - } else if (einProgress(error)) { - return false; - } else if (error != 0) { + } else if (error and not einProgress(error)) { throwIOException(e, socketErrorString(e, error)); } - return true; } bool @@ -426,12 +423,12 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, return s; } -extern "C" JNIEXPORT jboolean JNICALL +extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, jint socket) { - return doFinishConnect(e, socket); + doFinishConnect(e, socket); } extern "C" JNIEXPORT jint JNICALL diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 5dc6505877..b2ee0b7f75 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -54,7 +54,9 @@ public abstract class ClassLoader { throw new ClassNotFoundException(); } - protected abstract Class reallyFindLoadedClass(String name); + protected Class reallyFindLoadedClass(String name) { + return null; + } protected final Class findLoadedClass(String name) { return reallyFindLoadedClass(name); diff --git a/classpath/java/net/URLConnection.java b/classpath/java/net/URLConnection.java index ab8f5619e4..0219fbe688 100644 --- a/classpath/java/net/URLConnection.java +++ b/classpath/java/net/URLConnection.java @@ -16,6 +16,9 @@ import java.io.OutputStream; public abstract class URLConnection { protected final URL url; + protected boolean doInput = true; + protected boolean doOutput = false; + protected boolean useCaches = true; protected URLConnection(URL url) { this.url = url; @@ -29,6 +32,8 @@ public abstract class URLConnection { return -1; } + public abstract void connect() throws IOException; + public InputStream getInputStream() throws IOException { throw new UnknownServiceException(); } @@ -36,4 +41,24 @@ public abstract class URLConnection { public OutputStream getOutputStream() throws IOException { throw new UnknownServiceException(); } + + public boolean getDoInput() { + return doInput; + } + + public boolean getDoOutput() { + return doOutput; + } + + public void setDoInput(boolean v) { + doInput = v; + } + + public void setDoOutput(boolean v) { + doInput = v; + } + + public void setUseCaches(boolean v) { + useCaches = v; + } } diff --git a/classpath/java/nio/channels/Channels.java b/classpath/java/nio/channels/Channels.java index 3f7fe63eaa..849a16dffc 100644 --- a/classpath/java/nio/channels/Channels.java +++ b/classpath/java/nio/channels/Channels.java @@ -24,6 +24,14 @@ public class Channels { return new MyOutputStream(channel); } + public static ReadableByteChannel newChannel(InputStream stream) { + return new InputStreamChannel(stream); + } + + public static WritableByteChannel newChannel(OutputStream stream) { + return new OutputStreamChannel(stream); + } + private static class MyInputStream extends InputStream { private final ReadableByteChannel channel; @@ -72,4 +80,63 @@ public class Channels { channel.close(); } } + + private static class InputStreamChannel implements ReadableByteChannel { + private InputStream stream; + + public InputStreamChannel(InputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int read(ByteBuffer b) throws IOException { + int c = stream.read + (b.array(), b.arrayOffset() + b.position(), b.remaining()); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + } + + private static class OutputStreamChannel implements WritableByteChannel { + private OutputStream stream; + + public OutputStreamChannel(OutputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int write(ByteBuffer b) throws IOException { + stream.write(b.array(), b.arrayOffset() + b.position(), b.remaining()); + + int c = b.remaining(); + + b.position(b.limit()); + + return c; + } + } } diff --git a/classpath/java/nio/channels/GatheringByteChannel.java b/classpath/java/nio/channels/GatheringByteChannel.java new file mode 100644 index 0000000000..5696f5e980 --- /dev/null +++ b/classpath/java/nio/channels/GatheringByteChannel.java @@ -0,0 +1,20 @@ +/* Copyright (c) 2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface GatheringByteChannel extends WritableByteChannel { + public long write(ByteBuffer[] srcs) throws IOException; + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; +} diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index a8dc302dc7..734bce9fc8 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -19,6 +19,8 @@ public abstract class SelectableChannel implements Channel { abstract int socketFD(); + abstract void handleReadyOps(int ops); + public abstract SelectableChannel configureBlocking(boolean v) throws IOException; diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 7aa806886c..53e6eec36d 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -32,6 +32,10 @@ public class ServerSocketChannel extends SelectableChannel { return channel.socketFD(); } + public void handleReadyOps(int ops) { + channel.handleReadyOps(ops); + } + public SelectableChannel configureBlocking(boolean v) throws IOException { return channel.configureBlocking(v); } diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index 4dbc352558..65c9768d88 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -18,12 +18,13 @@ import java.net.Socket; import java.nio.ByteBuffer; public class SocketChannel extends SelectableChannel - implements ReadableByteChannel, WritableByteChannel + implements ReadableByteChannel, GatheringByteChannel { public static final int InvalidSocket = -1; int socket = InvalidSocket; boolean connected = false; + boolean readyToConnect = false; boolean blocking = true; public static SocketChannel open() throws IOException { @@ -66,8 +67,23 @@ public class SocketChannel extends SelectableChannel public boolean finishConnect() throws IOException { if (! connected) { - connected = natFinishConnect(socket); + while (! readyToConnect) { + Selector selector = Selector.open(); + SelectionKey key = register(selector, SelectionKey.OP_CONNECT, null); + + if (blocking) { + selector.select(); + } else { + selector.selectNow(); + break; + } + } + + natFinishConnect(socket); + + connected = readyToConnect; } + return connected; } @@ -117,6 +133,23 @@ public class SocketChannel extends SelectableChannel return w; } + public long write(ByteBuffer[] srcs) throws IOException { + return write(srcs, 0, srcs.length); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + long total = 0; + for (int i = offset; i < offset + length; ++i) { + total += write(srcs[i]); + if (srcs[i].hasRemaining()) { + return total; + } + } + return total; + } + private void closeSocket() { natCloseSocket(socket); } @@ -125,6 +158,12 @@ public class SocketChannel extends SelectableChannel return socket; } + void handleReadyOps(int ops) { + if ((ops & SelectionKey.OP_CONNECT) != 0) { + readyToConnect = true; + } + } + public class Handle extends Socket { public void setTcpNoDelay(boolean on) throws SocketException { natSetTcpNoDelay(socket, on); @@ -139,7 +178,7 @@ public class SocketChannel extends SelectableChannel private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected) throws IOException; - private static native boolean natFinishConnect(int socket) + private static native void natFinishConnect(int socket) throws IOException; private static native int natRead(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; diff --git a/classpath/java/nio/channels/SocketSelector.java b/classpath/java/nio/channels/SocketSelector.java index 27daf2670b..2482d0f180 100644 --- a/classpath/java/nio/channels/SocketSelector.java +++ b/classpath/java/nio/channels/SocketSelector.java @@ -96,6 +96,7 @@ class SocketSelector extends Selector { int ready = natUpdateReadySet(socket, key.interestOps(), state); key.readyOps(ready); if (ready != 0) { + c.handleReadyOps(ready); selectedKeys.add(key); } } diff --git a/test/DefineClass.java b/test/DefineClass.java new file mode 100644 index 0000000000..0b72cd5b95 --- /dev/null +++ b/test/DefineClass.java @@ -0,0 +1,86 @@ +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; + +public class DefineClass { + private static File findClass(String name, File directory) { + File[] files = directory.listFiles(); + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().equals(name + ".class")) { + return file; + } + } else if (file.isDirectory()) { + File result = findClass(name, file); + if (result != null) { + return result; + } + } + } + return null; + } + + private static byte[] read(File file) throws IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream in = new FileInputStream(file); + try { + if (in.read(bytes) != (int) file.length()) { + throw new RuntimeException(); + } + return bytes; + } finally { + in.close(); + } + } + + private static Class loadClass(String name) throws Exception { + return new MyClassLoader(DefineClass.class.getClassLoader()).defineClass + (name, read(findClass(name, new File(System.getProperty("user.dir"))))); + } + + private static void testStatic() throws Exception { + loadClass("DefineClass$Hello") + .getMethod("main", String[].class).invoke(null, (Object) new String[0]); + } + + private static void testDerived() throws Exception { + System.out.println + (String.valueOf + (((Base) loadClass("DefineClass$Derived").newInstance()).zip())); + } + + public static void main(String[] args) throws Exception { + testStatic(); + testDerived(); + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] bytes) { + return super.defineClass(name, bytes, 0, bytes.length); + } + } + + public static class Hello { + public static void main(String[] args) { + System.out.println("hello, world!"); + } + } + + public abstract static class Base { + public int foo; + + public void bar() { } + + public abstract int zip(); + } + + public static class Derived extends Base { + public int zip() { + return 42; + } + } +} diff --git a/test/FileOutput.java b/test/FileOutput.java index db4273f650..fa2cc0965e 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -4,14 +4,9 @@ import java.io.File; import java.io.IOException; public class FileOutput { - - /** - * @param args - * @throws IOException - */ - public static void main(String[] args) throws IOException { + private static void test(boolean appendFirst) throws IOException { try { - FileOutputStream f = new FileOutputStream("test.txt"); + FileOutputStream f = new FileOutputStream("test.txt", appendFirst); f.write("Hello world!\n".getBytes()); f.close(); @@ -37,4 +32,9 @@ public class FileOutput { } } + public static void main(String[] args) throws IOException { + test(false); + test(true); + } + }