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/06/25 07:19:51 UTC
svn commit: r1496353 - in /subversion/trunk/subversion/bindings/javahl:
native/JNIUtil.cpp native/JNIUtil.h
src/org/apache/subversion/javahl/ClientException.java
Author: brane
Date: Tue Jun 25 05:19:50 2013
New Revision: 1496353
URL: http://svn.apache.org/r1496353
Log:
Extend the JavaHL native exception to provide the whole stack of error
messages that were generated by the native libraries.
[in subversion/bindings/javahl/native]
* JNIUtil.h (message_stack_item, error_message_stack_t): New types.
(JNIUtil::assembleErrorMessage): Take an optional mesage_stack parameter.
* JNIUtil.cpp (construct_Jmessage_stack): New helper; converts an
error_message_stack_t to a Java list.
(JNIUtil::handleSVNError): Pass a message stack to assembleErrorMessage
and send the converted Java list to the ClientException constructor.
(JNIUtil::assembleErrorMessage): Optionally build the message stack.
[in subversion/bindings/javahl/src/org/apache/subversion/javahl]
* ClientException.java (ClientException): Update serialVersionUID.
(ClientException.ErrorMessage): New nested class. This is the Java
equivalent of the message_stack_item from JNIUtil.h.
(ClientException::ClientException): New constructor accepts a message stack.
(ClientException::getAllMessages): Return the current message stack.
Modified:
subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp
subversion/trunk/subversion/bindings/javahl/native/JNIUtil.h
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java
Modified: subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp?rev=1496353&r1=1496352&r2=1496353&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp Tue Jun 25 05:19:50 2013
@@ -418,10 +418,66 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
env->DeleteLocalRef(jfileName);
}
+namespace {
+jobject construct_Jmessage_stack(
+ const JNIUtil::error_message_stack_t& message_stack)
+{
+ JNIEnv *env = JNIUtil::getEnv();
+ env->PushLocalFrame(LOCAL_FRAME_SIZE);
+ if (JNIUtil::isJavaExceptionThrown())
+ return NULL;
+
+ jclass list_clazz = env->FindClass("java/util/ArrayList");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jmethodID mid = env->GetMethodID(list_clazz, "<init>", "(I)V");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jmethodID add_mid = env->GetMethodID(list_clazz, "add",
+ "(Ljava/lang/Object;)Z");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jobject jlist = env->NewObject(list_clazz, mid, jint(message_stack.size()));
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ jclass clazz = env->FindClass(JAVA_PACKAGE"/ClientException$ErrorMessage");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ mid = env->GetMethodID(clazz, "<init>",
+ "(ILjava/lang/String;Z)V");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ for (JNIUtil::error_message_stack_t::const_iterator
+ it = message_stack.begin();
+ it != message_stack.end(); ++it)
+ {
+ jobject jmessage = JNIUtil::makeJString(it->m_message.c_str());
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jobject jitem = env->NewObject(clazz, mid,
+ jint(it->m_code), jmessage,
+ jboolean(it->m_generic));
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ env->CallBooleanMethod(jlist, add_mid, jitem);
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ env->DeleteLocalRef(jmessage);
+ env->DeleteLocalRef(jitem);
+ }
+ return env->PopLocalFrame(jlist);
+}
+} // anonymous namespace
+
void JNIUtil::handleSVNError(svn_error_t *err)
{
std::string msg;
- assembleErrorMessage(svn_error_purge_tracing(err), 0, APR_SUCCESS, msg);
+ error_message_stack_t message_stack;
+ assembleErrorMessage(svn_error_purge_tracing(err),
+ 0, APR_SUCCESS, msg, &message_stack);
const char *source = NULL;
#ifdef SVN_DEBUG
#ifndef SVN_ERR__TRACING
@@ -472,12 +528,18 @@ void JNIUtil::handleSVNError(svn_error_t
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
+ jobject jmessageStack = construct_Jmessage_stack(message_stack);
+ if (isJavaExceptionThrown())
+ POP_AND_RETURN_NOTHING();
+
jmethodID mid = env->GetMethodID(clazz, "<init>",
- "(Ljava/lang/String;Ljava/lang/String;I)V");
+ "(Ljava/lang/String;"
+ "Ljava/lang/String;I"
+ "Ljava/util/List;)V");
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
jobject nativeException = env->NewObject(clazz, mid, jmessage, jsource,
- static_cast<jint>(err->apr_err));
+ jint(err->apr_err), jmessageStack);
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
@@ -875,13 +937,15 @@ jbyteArray JNIUtil::makeJByteArray(const
* @param parent_apr_err the apr of the previous level, used for formating
* @param buffer the buffer where the formated error message will
* be stored
+ * @param message_stack an array of error codes and messages
*/
void JNIUtil::assembleErrorMessage(svn_error_t *err, int depth,
apr_status_t parent_apr_err,
- std::string &buffer)
+ std::string &buffer,
+ error_message_stack_t* message_stack)
{
// buffer for a single error message
- char errbuf[256];
+ char errbuf[1024];
/* Pretty-print the error */
/* Note: we can also log errors here someday. */
@@ -890,35 +954,43 @@ void JNIUtil::assembleErrorMessage(svn_e
* the same as before. */
if (depth == 0 || err->apr_err != parent_apr_err)
{
+ const char *message;
/* Is this a Subversion-specific error code? */
if ((err->apr_err > APR_OS_START_USEERR)
&& (err->apr_err <= APR_OS_START_CANONERR))
- buffer.append(svn_strerror(err->apr_err, errbuf, sizeof(errbuf)));
+ message = svn_strerror(err->apr_err, errbuf, sizeof(errbuf));
/* Otherwise, this must be an APR error code. */
else
{
/* Messages coming from apr_strerror are in the native
encoding, it's a good idea to convert them to UTF-8. */
- const char* utf8_message;
apr_strerror(err->apr_err, errbuf, sizeof(errbuf));
- svn_error_t* utf8_err = svn_utf_cstring_to_utf8(
- &utf8_message, errbuf, err->pool);
+ svn_error_t* utf8_err =
+ svn_utf_cstring_to_utf8(&message, errbuf, err->pool);
if (utf8_err)
{
/* Use fuzzy transliteration instead. */
svn_error_clear(utf8_err);
- utf8_message = svn_utf_cstring_from_utf8_fuzzy(errbuf, err->pool);
+ message = svn_utf_cstring_from_utf8_fuzzy(errbuf, err->pool);
}
- buffer.append(utf8_message);
}
+
+ if (message_stack)
+ message_stack->push_back(
+ message_stack_item(err->apr_err, message, true));
+ buffer.append(message);
buffer.append("\n");
}
if (err->message)
- buffer.append(_("svn: ")).append(err->message).append("\n");
+ {
+ if (message_stack)
+ message_stack->push_back(
+ message_stack_item(err->apr_err, err->message));
+ buffer.append(_("svn: ")).append(err->message).append("\n");
+ }
if (err->child)
assembleErrorMessage(err->child, depth + 1, err->apr_err, buffer);
-
}
/**
Modified: subversion/trunk/subversion/bindings/javahl/native/JNIUtil.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/JNIUtil.h?rev=1496353&r1=1496352&r2=1496353&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/JNIUtil.h (original)
+++ subversion/trunk/subversion/bindings/javahl/native/JNIUtil.h Tue Jun 25 05:19:50 2013
@@ -37,6 +37,7 @@ class SVNBase;
#include <fstream>
#include <apr_time.h>
#include <string>
+#include <vector>
struct svn_error_t;
#define JAVA_PACKAGE "org/apache/subversion/javahl"
@@ -141,10 +142,26 @@ class JNIUtil
enum { formatBufferSize = 2048 };
enum { noLog, errorLog, exceptionLog, entryLog } LogLevel;
+ struct message_stack_item
+ {
+ apr_status_t m_code;
+ std::string m_message;
+ bool m_generic;
+
+ message_stack_item(apr_status_t code, const char* message,
+ bool generic = false)
+ : m_code(code),
+ m_message(message),
+ m_generic(generic)
+ {}
+ };
+ typedef std::vector<message_stack_item> error_message_stack_t;
+
private:
static void assembleErrorMessage(svn_error_t *err, int depth,
apr_status_t parent_apr_err,
- std::string &buffer);
+ std::string &buffer,
+ error_message_stack_t* message_stack = NULL);
static void putErrorsInTrace(svn_error_t *err,
std::vector<jobject> &stackTrace);
/**
Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java?rev=1496353&r1=1496352&r2=1496353&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java Tue Jun 25 05:19:50 2013
@@ -22,6 +22,7 @@
*/
package org.apache.subversion.javahl;
+import java.util.List;
/**
* This exception is thrown whenever something goes wrong in the
@@ -36,7 +37,54 @@ public class ClientException extends Nat
// http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf
// http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html#6678
// http://java.sun.com/javase/6/docs/platform/serialization/spec/version.html#6678
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
+
+ /**
+ * Describes a single error message in a stack of messages
+ * associated with this exception.
+ * @since 1.9
+ */
+ public static final class ErrorMessage
+ {
+ ErrorMessage(int code, String message, boolean generic)
+ {
+ this.code = code;
+ this.message = message;
+ this.generic = generic;
+ }
+
+ /** @return The APR error code associated with the message. */
+ public final int getCode() { return code; }
+
+ /** @return The error message text. */
+ public final String getMessage() { return message; }
+
+ /** @return A flag indicating whether this is a generic
+ message for the APR error code, or a more specific message
+ generated by the native libraries. */
+ public final boolean isGeneric() { return generic; }
+
+ private final int code;
+ private final String message;
+ private final boolean generic;
+ };
+
+ /**
+ * This constructor is only used by the native library.
+ *
+ * @param message A description of the problem.
+ * @param source The error's source.
+ * @param aprError Any associated APR error code for a wrapped
+ * <code>svn_error_t</code>.
+ * @param messageStack The whole stack of error messages
+ * @since 1.9
+ */
+ ClientException(String message, String source, int aprError,
+ List<ErrorMessage> messageStack)
+ {
+ super(message, source, aprError);
+ this.messageStack = messageStack;
+ }
/**
* This constructor is only used by the native library.
@@ -48,7 +96,12 @@ public class ClientException extends Nat
*/
ClientException(String message, String source, int aprError)
{
- super(message, source, aprError);
+ this(message, source, aprError, null);
+ }
+
+ public List<ErrorMessage> getAllMessages()
+ {
+ return messageStack;
}
/**
@@ -68,4 +121,6 @@ public class ClientException extends Nat
return new ClientException(t.getMessage(), null, -1);
}
}
+
+ private final List<ErrorMessage> messageStack;
}