You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/11/11 17:41:27 UTC
svn commit: r1540764 - in
/subversion/trunk/subversion/bindings/javahl/native: ./ jniwrapper/
Author: brane
Date: Mon Nov 11 16:41:27 2013
New Revision: 1540764
URL: http://svn.apache.org/r1540764
Log:
Add a proper channel wrapper to JavaHL, and use it to implement the
tunnel agent callbacks.
* subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp,
subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp:
New; channel wrapper implementation.
* subversion/bindings/javahl/native/jniwrapper/jni_env.hpp
(Java::Env::GetDirectBufferAddress): New JNI function wrapper.
* subversion/bindings/javahl/native/jniwrapper/jni_array.hpp
(Java::ByteArray::ByteArray): New constructor for uninitialized arrays.
* subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp
(Java::IOException): New exception generator.
* subversion/bindings/javahl/native/jniwrapper/jni_base.cpp
(Java::IOException::m_class_name): Initialize.
* subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp:
Reimplement everything using the new channel wrapper and jniwrapper.
Added:
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp
Modified:
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_array.hpp
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_base.cpp
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_env.hpp
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp
Modified: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_array.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_array.hpp?rev=1540764&r1=1540763&r2=1540764&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_array.hpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_array.hpp Mon Nov 11 16:41:27 2013
@@ -52,6 +52,15 @@ public:
{}
/**
+ * Constructs a new, uninitialized array of size @a length.
+ */
+ explicit ByteArray(Env env, jsize length)
+ : m_env(env),
+ m_length(length),
+ m_array(m_env.NewByteArray(m_length))
+ {}
+
+ /**
* Constructs a new array and wrapper from @a text.
*/
explicit ByteArray(Env env, const char* text)
Modified: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_base.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_base.cpp?rev=1540764&r1=1540763&r2=1540764&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_base.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_base.cpp Mon Nov 11 16:41:27 2013
@@ -205,6 +205,9 @@ const char* const NullPointerException::
const char* const OutOfMemoryError::m_class_name =
"java/lang/OutOfMemoryError";
+const char* const IOException::m_class_name =
+ "java/io/IOException";
+
} // namespace Java
Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp?rev=1540764&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.cpp Mon Nov 11 16:41:27 2013
@@ -0,0 +1,254 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include <stdexcept>
+
+#include "jni_array.hpp"
+#include "jni_channel.hpp"
+
+#include "svn_private_config.h"
+
+namespace Java {
+
+namespace {
+// Get the ByteBuffer's internal array.
+jbyteArray get_array(Env env, jclass cls, jobject buffer,
+ MethodID& mid_has_array, MethodID& mid_get_array)
+{
+ if (!mid_has_array)
+ mid_has_array = env.GetMethodID(cls, "hasArray", "()Z");
+ if (!env.CallBooleanMethod(buffer, mid_has_array))
+ return NULL;
+
+ if (!mid_get_array)
+ mid_get_array = env.GetMethodID(cls, "array", "()[B");
+ return jbyteArray(env.CallObjectMethod(buffer, mid_get_array));
+}
+
+// Get the offset in the ByteBuffer's array. NEVER call this function
+// unless the buffer actually has an accessible array.
+jint get_array_offset(Env env, jclass cls, jobject buffer,
+ MethodID& mid_get_array_offset)
+{
+ if (!mid_get_array_offset)
+ mid_get_array_offset = env.GetMethodID(cls, "arrayOffset", "()I");
+ return env.CallIntMethod(buffer, mid_get_array_offset);
+}
+
+// Get the remaining space in a ByteBuffer.
+jint get_remaining(Env env, jclass cls, jobject buffer,
+ MethodID& mid_get_remaining)
+{
+ if (!mid_get_remaining)
+ mid_get_remaining = env.GetMethodID(cls, "remaining", "()I");
+ return env.CallIntMethod(buffer, mid_get_remaining);
+}
+
+// Get the current position of a ByteBuffer.
+jint get_position(Env env, jclass cls, jobject buffer,
+ MethodID& mid_get_position)
+{
+ if (!mid_get_position)
+ mid_get_position = env.GetMethodID(cls, "position", "()I");
+ return env.CallIntMethod(buffer, mid_get_position);
+}
+
+// Set the new position of a ByteBuffer.
+void set_position(Env env, jclass cls, jobject buffer,
+ MethodID& mid_set_position,
+ jint new_position)
+{
+ if (!mid_set_position)
+ mid_set_position = env.GetMethodID(cls, "position",
+ "(I)Ljava/nio/Buffer;");
+ env.CallObjectMethod(buffer, mid_set_position, new_position);
+}
+
+// Get byte array contents from a ByteBuffer.
+void get_bytearray(Env env, jclass cls, jobject buffer,
+ MethodID& mid_get_bytearray,
+ ByteArray& array, jint length = -1, jint offset = 0)
+{
+ if (!mid_get_bytearray)
+ mid_get_bytearray = env.GetMethodID(cls, "get",
+ "([BII)Ljava/nio/ByteBuffer;");
+ env.CallObjectMethod(
+ buffer, mid_get_bytearray, array.get(), offset,
+ (length >= 0 ? length : (array.length() - offset)));
+}
+
+// Put byte array contents into a ByteBuffer.
+void put_bytearray(Env env, jclass cls, jobject buffer,
+ MethodID& mid_put_bytearray,
+ ByteArray& array, jint length = -1, jint offset = 0)
+{
+ if (!mid_put_bytearray)
+ mid_put_bytearray = env.GetMethodID(cls, "put",
+ "([BII)Ljava/nio/ByteBuffer;");
+ env.CallObjectMethod(buffer, mid_put_bytearray,
+ array.get(), offset,
+ (length >= 0 ? length : (array.length() - offset)));
+}
+
+struct BadReaderWriter : public ChannelReader, ChannelWriter
+{
+ BadReaderWriter() {}
+
+ virtual jint operator()(Env, void*, jint)
+ {
+ throw std::logic_error(_("Reading from write-only channel"));
+ }
+
+ virtual jint operator()(Env, const void*, jint)
+ {
+ throw std::logic_error(_("Writing to read-only channel"));
+ }
+} bad_reader_writer;
+
+} // anonymous namespace
+
+
+ChannelReader& ByteChannel::m_null_reader = bad_reader_writer;
+ChannelWriter& ByteChannel::m_null_writer = bad_reader_writer;
+
+const char* const ByteChannel::m_byte_buffer_class_name =
+ "java/nio/ByteBuffer";
+
+jint ByteChannel::read(jobject destination)
+{
+ const jint remaining = get_remaining(m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_get_remaining);
+ if (!remaining)
+ {
+ // No space in the buffer; don't try to read anything.
+ return 0;
+ }
+
+ const jint position = get_position(m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_get_position);
+
+ jint bytes_read = 0;
+ void* data = m_env.GetDirectBufferAddress(destination);
+ if (data)
+ {
+ data = static_cast<char*>(data) + position;
+ bytes_read = m_reader(m_env, data, remaining);
+ }
+ else
+ {
+ // It was not a direct buffer ... see if it has an array.
+ jbyteArray raw_array = get_array(m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_has_array,
+ m_mid_byte_buffer_get_array);
+ if (raw_array)
+ {
+ const jint array_offset = get_array_offset(
+ m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_get_array_offset);
+ ByteArray array(m_env, raw_array);
+ ByteArray::MutableContents contents(array);
+ data = contents.data();
+ data = static_cast<char*>(data) + position + array_offset;
+ bytes_read = m_reader(m_env, data, remaining);
+ }
+ }
+ if (data)
+ {
+ if (bytes_read > 0)
+ set_position(m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_set_position,
+ position + bytes_read);
+ return bytes_read;
+ }
+
+ // No accessible array, either. Oh well. Create a byte array and
+ // push it into the buffer.
+ ByteArray array(m_env, remaining);
+ ByteArray::MutableContents contents(array);
+ bytes_read = m_reader(m_env, contents.data(), contents.length());
+ if (bytes_read > 0)
+ put_bytearray(m_env, m_cls_byte_buffer, destination,
+ m_mid_byte_buffer_put_bytearray,
+ array, bytes_read);
+ return bytes_read;
+}
+
+jint ByteChannel::write(jobject source)
+{
+ const jint remaining = get_remaining(m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_get_remaining);
+ if (!remaining)
+ {
+ // No data in the buffer; don't try to write anything.
+ return 0;
+ }
+
+ const jint position = get_position(m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_get_position);
+
+ jint bytes_written = 0;
+ const void* data = m_env.GetDirectBufferAddress(source);
+ if (data)
+ {
+ data = static_cast<const char*>(data) + position;
+ bytes_written = m_writer(m_env, data, remaining);
+ }
+ else
+ {
+ // It was not a direct buffer ... see if it has an array.
+ jbyteArray raw_array = get_array(m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_has_array,
+ m_mid_byte_buffer_get_array);
+ if (raw_array)
+ {
+ const jint array_offset = get_array_offset(
+ m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_get_array_offset);
+ const ByteArray array(m_env, raw_array);
+ ByteArray::Contents contents(array);
+ data = contents.data();
+ data = static_cast<const char*>(data) + position + array_offset;
+ bytes_written = m_writer(m_env, data, remaining);
+ }
+ }
+ if (data)
+ {
+ if (bytes_written > 0)
+ set_position(m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_set_position,
+ position + bytes_written);
+ return bytes_written;
+ }
+
+ // No accessible array, either. Oh well. Get an array from the
+ // buffer and read data from that.
+ ByteArray array(m_env, remaining);
+ get_bytearray(m_env, m_cls_byte_buffer, source,
+ m_mid_byte_buffer_get_bytearray,
+ array);
+ ByteArray::Contents contents(array);
+ bytes_written = m_writer(m_env, contents.data(), contents.length());
+ return bytes_written;
+}
+
+} // namespace Java
Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp?rev=1540764&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_channel.hpp Mon Nov 11 16:41:27 2013
@@ -0,0 +1,202 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#ifndef SVN_JAVAHL_JNIWRAPPER_CHANNEL_HPP
+#define SVN_JAVAHL_JNIWRAPPER_CHANNEL_HPP
+
+#include "jni_env.hpp"
+
+namespace Java {
+
+/**
+ * Abstract base class for implementing channel read method internals.
+ *
+ * @since New in 1.9.
+ */
+struct ChannelReader
+{
+ /**
+ * Reads at most @a length bytes into @a buffer, returning the
+ * number of bytes read (which may be zero) or -1 if at
+ * end-of-stream.
+ */
+ virtual jint operator()(Env env, void* buffer, jint length) = 0;
+};
+
+/**
+ * Abstract base class for implementing channel write method internals.
+ *
+ * @since New in 1.9.
+ */
+struct ChannelWriter
+{
+ /**
+ * Writes at exactly @a length bytes from @a buffer, returning the
+ * number of bytes written (which may be zero).
+ */
+ virtual jint operator()(Env env, const void* buffer, jint length) = 0;
+};
+
+
+/**
+ * Wrapper for @c java.nio.channels.ByteChannel. Unlike most wrappers,
+ * this one does not actually represent a ByteChannel object. The
+ * assumption is that the native implementation will want to implement
+ * the read and write methods, not invoke them.
+ *
+ * Also serves as the (protected) base of the Readable- and
+ * WritableByteChannel interfaces; this is for purposes of code
+ * sharing only. We're not interested in replicating Java's class
+ * hierarchy here.
+ *
+ * @since New in 1.9.
+ */
+class ByteChannel
+{
+public:
+ /**
+ * Constructs a wrapper for @a channel with @a reader and @a writer
+ * as the read and write method implementations.
+ */
+ explicit ByteChannel(Env env, ChannelReader& reader, ChannelWriter& writer)
+ : m_env(env),
+ m_reader(reader),
+ m_writer(writer),
+ m_cls_byte_buffer(env.FindClass(m_byte_buffer_class_name))
+ {}
+
+ /**
+ * Reads bytes into @a destination, which must be a
+ * @c java.nio.ByteBuffer instance, from #m_reader.
+ * @return the number of bytes read, or -1 if at end-of-stream.
+ */
+ jint read(jobject destination);
+
+ /**
+ * Writes bytes from @a source, which must be a
+ * @c java.nio.ByteBuffer instance, to #m_writer.
+ * @return the number of bytes written.
+ */
+ jint write(jobject source);
+
+protected:
+ /**
+ * Constructor used by read-only subclasses.
+ */
+ explicit ByteChannel(Env env, ChannelReader& reader)
+ : m_env(env),
+ m_reader(reader),
+ m_writer(m_null_writer),
+ m_cls_byte_buffer(env.FindClass(m_byte_buffer_class_name))
+ {}
+
+ /**
+ * Constructor used by write-only subclasses.
+ */
+ explicit ByteChannel(Env env, ChannelWriter& writer)
+ : m_env(env),
+ m_reader(m_null_reader),
+ m_writer(writer),
+ m_cls_byte_buffer(env.FindClass(m_byte_buffer_class_name))
+ {}
+
+private:
+ Env m_env;
+ ChannelReader& m_reader;
+ ChannelWriter& m_writer;
+
+ static ChannelReader& m_null_reader;
+ static ChannelWriter& m_null_writer;
+
+ // Private references for the java.nio.ByteBuffer class.
+ static const char* const m_byte_buffer_class_name;
+ const jclass m_cls_byte_buffer;
+ MethodID m_mid_byte_buffer_has_array;
+ MethodID m_mid_byte_buffer_get_array;
+ MethodID m_mid_byte_buffer_get_array_offset;
+ MethodID m_mid_byte_buffer_get_remaining;
+ MethodID m_mid_byte_buffer_get_position;
+ MethodID m_mid_byte_buffer_set_position;
+ MethodID m_mid_byte_buffer_get_bytearray;
+ MethodID m_mid_byte_buffer_put_bytearray;
+};
+
+
+/**
+ * Wrapper for @c java.nio.channels.ReadableByteChannel.
+ *
+ * @since New in 1.9.
+ */
+class ReadableByteChannel : protected ByteChannel
+{
+public:
+ /**
+ * Constructs a wrapper for @a channel with @a reader the read
+ * method implementation.
+ */
+ explicit ReadableByteChannel(Env env, ChannelReader& reader)
+ : ByteChannel(env, reader)
+ {}
+
+ /**
+ * Reads bytes into @a destination, which must be a
+ * @c java.nio.ByteBuffer instance, from #m_reader.
+ * @return the number of bytes read, or -1 if at end-of-stream.
+ */
+ jint read(jobject destination)
+ {
+ return ByteChannel::read(destination);
+ }
+};
+
+
+/**
+ * Wrapper @c java.nio.channels.WritableByteChannel.
+ *
+ * @since New in 1.9.
+ */
+class WritableByteChannel : protected ByteChannel
+{
+public:
+ /**
+ * Constructs a wrapper for @a channel with @a writer as the write
+ * method implementation.
+ */
+ explicit WritableByteChannel(Env env, ChannelWriter& writer)
+ : ByteChannel(env, writer)
+ {}
+
+ /**
+ * Writes bytes from @a source, which must be a
+ * @c java.nio.ByteBuffer instance, to #m_writer.
+ * @return the number of bytes written.
+ */
+ jint write(jobject source)
+ {
+ return ByteChannel::write(source);
+ }
+};
+
+} // namespace Java
+
+#endif // SVN_JAVAHL_JNIWRAPPER_CHANNEL_HPP
Modified: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_env.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_env.hpp?rev=1540764&r1=1540763&r2=1540764&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_env.hpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_env.hpp Mon Nov 11 16:41:27 2013
@@ -509,6 +509,14 @@ public:
SVN_JAVAHL_JNIWRAPPER_PRIMITIVE_TYPE_ARRAY(jdouble, Double)
#undef SVN_JAVAHL_JNIWRAPPER_PRIMITIVE_TYPE_ARRAY
+ /** Wrapped JNI function. */
+ void* GetDirectBufferAddress(jobject buffer) const
+ {
+ void* const addr = m_env->GetDirectBufferAddress(buffer);
+ check_java_exception();
+ return addr;
+ }
+
private:
::JNIEnv* m_env;
static ::JavaVM* m_jvm;
Modified: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp?rev=1540764&r1=1540763&r2=1540764&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_exception.hpp Mon Nov 11 16:41:27 2013
@@ -206,6 +206,25 @@ private:
static const char* const m_class_name;
};
+/**
+ * Generator class for exceptions of type @c java.io.IOException.
+ *
+ * @since New in 1.9.
+ */
+class IOException : public Exception
+{
+public:
+ /**
+ * Constructs an exception generator object.
+ */
+ explicit IOException(Env env)
+ : Exception(env, m_class_name)
+ {}
+
+private:
+ static const char* const m_class_name;
+};
+
} // namespace Java
#endif // SVN_JAVAHL_JNIWRAPPER_ENV_HPP
Modified: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp?rev=1540764&r1=1540763&r2=1540764&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_TunnelChannel.cpp Mon Nov 11 16:41:27 2013
@@ -25,8 +25,6 @@
* TunnelChannel, RequestChannel and ResponseChannel
*/
-#include <assert.h> // TEMPORARY until we handle weird byte arrays
-
#include <string>
#include <apr_file_io.h>
@@ -35,191 +33,142 @@
#include "../include/org_apache_subversion_javahl_util_RequestChannel.h"
#include "../include/org_apache_subversion_javahl_util_ResponseChannel.h"
-#include "JNIUtil.h"
-#include "JNIStackElement.h"
-#include "JNIByteArray.h"
+#include "jniwrapper/jni_exception.hpp"
+#include "jniwrapper/jni_channel.hpp"
+#include "jniwrapper/jni_stack.hpp"
#include "svn_private_config.h"
namespace {
-apr_file_t* get_file_descriptor(jlong jfd)
+apr_file_t* get_file_descriptor(Java::Env env, jlong jfd)
{
apr_file_t* fd = reinterpret_cast<apr_file_t*>(jfd);
if (!fd)
- {
- JNIUtil::throwNullPointerException("nativeChannel");
- return NULL;
- }
+ Java::NullPointerException(env).raise("nativeChannel");
return fd;
}
-void throw_IOException(const char* message, apr_status_t status)
+void throw_IOException(Java::Env env, const char* message,
+ apr_status_t status)
{
+ char buf[1024];
std::string msg(message);
- if (status)
- {
- char buf[1024];
- apr_strerror(status, buf, sizeof(buf) - 1);
- msg += ": ";
- msg += buf;
- }
- JNIUtil::raiseThrowable("java/io/IOException", msg.c_str());
+ apr_strerror(status, buf, sizeof(buf) - 1);
+ msg += buf;
+ Java::IOException(env).raise(msg.c_str());
}
-class ByteBufferProxy
+class TunnelReader : public Java::ChannelReader
{
public:
- ByteBufferProxy(jobject buf, JNIEnv* env)
- : m_buf(buf),
- m_direct(env->GetDirectBufferAddress(buf)),
- m_array(m_direct ? NULL : get_array(buf, env)),
- m_array_offset(m_array ? get_array_offset(buf, env) : 0),
- m_offset(get_position(buf, env)),
- m_size(get_remaining(buf, env))
+ explicit TunnelReader(Java::Env env, jlong jnative_channel)
+ : m_fd(get_file_descriptor(env, jnative_channel))
{}
- jint read(apr_file_t* fd, JNIEnv* env)
+ virtual jint operator()(Java::Env env, void* buffer, jint length)
{
- if (!m_size)
+ if (!length)
return 0;
- JNIByteArray arr(m_array, false, false);
- apr_size_t bytes_read = m_size;
- apr_status_t status = apr_file_read(
- fd, get_base_address(arr), &bytes_read);
+ apr_size_t bytes_read = length;
+ const apr_status_t status = apr_file_read(m_fd, buffer, &bytes_read);
if (status && !APR_STATUS_IS_EOF(status))
{
- throw_IOException(_("Error reading from native file handle"),
- status);
- return 0;
+ throw_IOException(
+ env, _("Error reading from native file handle: "),
+ status);
+ return -1;
}
- update_position(bytes_read, env);
+ if (APR_STATUS_IS_EOF(status))
+ return -1;
return jint(bytes_read);
}
- jint write(apr_file_t* fd, JNIEnv* env)
+private:
+ apr_file_t* const m_fd;
+};
+
+class TunnelWriter : public Java::ChannelWriter
+{
+public:
+ explicit TunnelWriter(Java::Env env, jlong jnative_channel)
+ : m_fd(get_file_descriptor(env, jnative_channel))
+ {}
+
+ virtual jint operator()(Java::Env env, const void* buffer, jint length)
{
- if (!m_size)
+ if (!length)
return 0;
- JNIByteArray arr(m_array);
apr_size_t bytes_written;
- apr_status_t status = apr_file_write_full(
- fd, get_base_address(arr), m_size, &bytes_written);
+ const apr_status_t status =
+ apr_file_write_full(m_fd, buffer, length, &bytes_written);
if (status)
{
- throw_IOException(_("Error writing to native file handle"),
- status);
- return 0;
+ throw_IOException(
+ env, _("Error writing to native file handle: "),
+ status);
+ return -1;
}
- update_position(bytes_written, env);
return jint(bytes_written);
}
private:
- void *get_base_address(JNIByteArray& arr)
- {
- void* base = (m_direct ? m_direct
- : const_cast<signed char*>(arr.getBytes()));
- // FIXME: We do not currently support buffers that are nether
- // direct, nor have an accessible array.
- assert(base != 0);
- return static_cast<char*>(base) + m_offset + m_array_offset;
- }
-
- void update_position(apr_size_t amount, JNIEnv* env)
- {
- jmethodID mid = env->GetMethodID(
- env->GetObjectClass(m_buf), "position", "(I)Ljava/nio/Buffer;");
- if (mid)
- env->CallObjectMethod(m_buf, mid, jint(amount));
- }
-
- static jbyteArray get_array(jobject buf, JNIEnv* env)
- {
- jclass cls = env->GetObjectClass(buf);
- jmethodID mid = env->GetMethodID(cls, "hasArray", "()Z");
- if (!mid)
- return NULL;
-
- jboolean has_array = env->CallBooleanMethod(buf, mid);
- if (!has_array)
- return NULL;
-
- mid = env->GetMethodID(cls, "array", "()[B");
- if (mid)
- return jbyteArray(env->CallObjectMethod(buf, mid));
- return NULL;
- }
-
- static apr_size_t get_array_offset(jobject buf, JNIEnv* env)
- {
- jmethodID mid = env->GetMethodID(
- env->GetObjectClass(buf), "arrayOffset", "()I");
- if (mid)
- return env->CallIntMethod(buf, mid);
- return 0;
- }
-
- static apr_size_t get_position(jobject buf, JNIEnv* env)
- {
- jmethodID mid = env->GetMethodID(
- env->GetObjectClass(buf), "position", "()I");
- if (mid)
- return env->CallIntMethod(buf, mid);
- return 0;
- }
-
- static apr_size_t get_remaining(jobject buf, JNIEnv* env)
- {
- jmethodID mid = env->GetMethodID(
- env->GetObjectClass(buf), "remaining", "()I");
- if (mid)
- return env->CallIntMethod(buf, mid);
- return 0;
- }
-
- jobject m_buf;
- void *m_direct;
- jbyteArray m_array;
- apr_size_t m_array_offset;
- apr_size_t m_offset;
- apr_size_t m_size;
+ apr_file_t* const m_fd;
};
+
} // anonymous namespace
+
JNIEXPORT void JNICALL
Java_org_apache_subversion_javahl_util_TunnelChannel_nativeClose(
- JNIEnv* env, jclass jclazz, jlong nativeChannel)
+ JNIEnv* jenv, jclass jclazz, jlong jnative_channel)
{
- JNIEntryStatic(TunnelChannel, close);
- apr_file_t* fd = reinterpret_cast<apr_file_t*>(nativeChannel);
- if (!fd)
- return;
+ SVN_JAVAHL_JNI_TRY_STATIC(TunnelChannel, close)
+ {
+ const Java::Env env(jenv);
+
+ apr_file_t* const fd = get_file_descriptor(env, jnative_channel);
+ if (!fd)
+ return;
- apr_status_t status = apr_file_close(fd);
- if (status)
- throw_IOException(_("Error closing native file handle"), status);
+ const apr_status_t status = apr_file_close(fd);
+ if (status)
+ throw_IOException(
+ env, _("Error closing native file handle: "),
+ status);
+ }
+ SVN_JAVAHL_JNI_CATCH;
}
JNIEXPORT jint JNICALL
Java_org_apache_subversion_javahl_util_RequestChannel_nativeRead(
- JNIEnv* env, jclass jclazz, jlong nativeChannel, jobject dst)
+ JNIEnv* jenv, jclass jclazz, jlong jnative_channel, jobject jdst_buffer)
{
- JNIEntryStatic(RequestChannel, read);
- apr_file_t* fd = get_file_descriptor(nativeChannel);
- if (fd)
- return ByteBufferProxy(dst, env).read(fd, env);
+ SVN_JAVAHL_JNI_TRY_STATIC(RequestChannel, read)
+ {
+ const Java::Env env(jenv);
+
+ TunnelReader reader(env, jnative_channel);
+ Java::ReadableByteChannel channel(env, reader);
+ return channel.read(jdst_buffer);
+ }
+ SVN_JAVAHL_JNI_CATCH;
return -1;
}
JNIEXPORT jint JNICALL
Java_org_apache_subversion_javahl_util_ResponseChannel_nativeWrite(
- JNIEnv* env, jclass jclazz, jlong nativeChannel, jobject src)
+ JNIEnv* jenv, jclass jclazz, jlong jnative_channel, jobject jsrc_buffer)
{
- JNIEntryStatic(ResponseChannel, write);
- apr_file_t* fd = get_file_descriptor(nativeChannel);
- if (fd)
- return ByteBufferProxy(src, env).write(fd, env);
+ SVN_JAVAHL_JNI_TRY_STATIC(ResponseChannel, write)
+ {
+ const Java::Env env(jenv);
+
+ TunnelWriter writer(env, jnative_channel);
+ Java::WritableByteChannel channel(env, writer);
+ return channel.write(jsrc_buffer);
+ }
+ SVN_JAVAHL_JNI_CATCH;
return -1;
}