You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/15 10:52:18 UTC

svn commit: r1532250 [5/37] - in /subversion/branches/cache-server: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/emacs/ contrib/hook-scripts/ contrib/server-side/fsfsfixer/ contrib/ser...

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.cpp Tue Oct 15 08:52:06 2013
@@ -30,12 +30,14 @@
 #include "JNIStringHolder.h"
 #include "EnumMapper.h"
 #include "RevisionRange.h"
+#include "RevisionRangeList.h"
 #include "CreateJ.h"
 #include "../include/org_apache_subversion_javahl_types_Revision.h"
 #include "../include/org_apache_subversion_javahl_CommitItemStateFlags.h"
 
 #include "svn_path.h"
 #include "svn_props.h"
+#include "svn_mergeinfo.h"
 #include "private/svn_wc_private.h"
 
 jobject
@@ -230,6 +232,61 @@ CreateJ::Checksum(const svn_checksum_t *
 }
 
 jobject
+CreateJ::DirEntry(const char *path, const char *absPath,
+                  const svn_dirent_t *dirent)
+{
+  JNIEnv *env = JNIUtil::getEnv();
+
+  // Create a local frame for our references
+  env->PushLocalFrame(LOCAL_FRAME_SIZE);
+  if (JNIUtil::isJavaExceptionThrown())
+    return SVN_NO_ERROR;
+
+  jclass clazz = env->FindClass(JAVA_PACKAGE"/types/DirEntry");
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  static jmethodID mid = 0;
+  if (mid == 0)
+    {
+      mid = env->GetMethodID(clazz, "<init>",
+                             "(Ljava/lang/String;Ljava/lang/String;"
+                             "L"JAVA_PACKAGE"/types/NodeKind;"
+                             "JZJJLjava/lang/String;)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+    }
+
+  jstring jPath = JNIUtil::makeJString(path);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  jstring jAbsPath = JNIUtil::makeJString(absPath);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  jobject jNodeKind = EnumMapper::mapNodeKind(dirent->kind);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  jlong jSize = dirent->size;
+  jboolean jHasProps = (dirent->has_props? JNI_TRUE : JNI_FALSE);
+  jlong jLastChangedRevision = dirent->created_rev;
+  jlong jLastChanged = dirent->time;
+  jstring jLastAuthor = JNIUtil::makeJString(dirent->last_author);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  jobject ret = env->NewObject(clazz, mid, jPath, jAbsPath, jNodeKind,
+                               jSize, jHasProps, jLastChangedRevision,
+                               jLastChanged, jLastAuthor);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  return env->PopLocalFrame(ret);
+}
+
+jobject
 CreateJ::Info(const char *path, const svn_client_info2_t *info)
 {
   JNIEnv *env = JNIUtil::getEnv();
@@ -423,6 +480,72 @@ CreateJ::Lock(const svn_lock_t *lock)
 }
 
 jobject
+CreateJ::LockMap(const apr_hash_t *locks, apr_pool_t *pool)
+{
+  JNIEnv *env = JNIUtil::getEnv();
+
+  if (locks == NULL)
+    return NULL;
+
+  // Create a local frame for our references
+  env->PushLocalFrame(LOCAL_FRAME_SIZE);
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  jclass clazz = env->FindClass("java/util/HashMap");
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  static jmethodID init_mid = 0;
+  if (init_mid == 0)
+    {
+      init_mid = env->GetMethodID(clazz, "<init>", "()V");
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+    }
+
+  static jmethodID put_mid = 0;
+  if (put_mid == 0)
+    {
+      put_mid = env->GetMethodID(clazz, "put",
+                                 "(Ljava/lang/Object;Ljava/lang/Object;)"
+                                 "Ljava/lang/Object;");
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+    }
+
+  jobject map = env->NewObject(clazz, init_mid);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
+
+  apr_hash_index_t *hi;
+  int i = 0;
+  for (hi = apr_hash_first(pool, (apr_hash_t *) locks); hi;
+        hi = apr_hash_next(hi), ++i)
+    {
+      const char *key = (const char *) svn__apr_hash_index_key(hi);
+      const svn_lock_t *lock = (const svn_lock_t *) svn__apr_hash_index_val(hi);
+
+      jstring jpath = JNIUtil::makeJString(key);
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+
+      jobject jlock = Lock(lock);
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+
+      env->CallObjectMethod(map, put_mid, jpath, jlock);
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NULL;
+
+      env->DeleteLocalRef(jpath);
+      env->DeleteLocalRef(jlock);
+    }
+
+  return env->PopLocalFrame(map);
+}
+
+jobject
 CreateJ::ChangedPath(const char *path, svn_log_changed_path2_t *log_item)
 {
   JNIEnv *env = JNIUtil::getEnv();
@@ -655,7 +778,7 @@ CreateJ::ClientNotifyInformation(const s
                                "L"JAVA_PACKAGE"/types/NodeKind;"
                                "Ljava/lang/String;"
                                "L"JAVA_PACKAGE"/types/Lock;"
-                               "Ljava/lang/String;"
+                               "Ljava/lang/String;Ljava/util/List;"
                                "L"JAVA_PACKAGE"/ClientNotifyInformation$Status;"
                                "L"JAVA_PACKAGE"/ClientNotifyInformation$Status;"
                                "L"JAVA_PACKAGE"/ClientNotifyInformation$LockStatus;"
@@ -688,7 +811,9 @@ CreateJ::ClientNotifyInformation(const s
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
-  jstring jErr = JNIUtil::makeSVNErrorMessage(wcNotify->err);
+  jstring jErr;
+  jobject jErrStack;
+  JNIUtil::makeSVNErrorMessage(wcNotify->err, &jErr, &jErrStack);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
@@ -735,7 +860,7 @@ CreateJ::ClientNotifyInformation(const s
   jlong jhunkModifiedLength = wcNotify->hunk_modified_length;
   jlong jhunkMatchedLine = wcNotify->hunk_matched_line;
   jint jhunkFuzz = static_cast<jint>(wcNotify->hunk_fuzz);
-  if (jhunkFuzz != wcNotify->hunk_fuzz)
+  if (jhunkFuzz < 0 || jhunkFuzz != wcNotify->hunk_fuzz)
     {
       env->ThrowNew(env->FindClass("java.lang.ArithmeticException"),
                     "Overflow converting C svn_linenum_t to Java int");
@@ -744,7 +869,7 @@ CreateJ::ClientNotifyInformation(const s
 
   // call the Java method
   jobject jInfo = env->NewObject(clazz, midCT, jPath, jAction,
-                                 jKind, jMimeType, jLock, jErr,
+                                 jKind, jMimeType, jLock, jErr, jErrStack,
                                  jContentState, jPropState, jLockState,
                                  (jlong) wcNotify->revision, jChangelistName,
                                  jMergeRange, jpathPrefix, jpropName,
@@ -951,82 +1076,129 @@ CreateJ::CommitInfo(const svn_commit_inf
 }
 
 jobject
-CreateJ::RevisionRangeList(svn_rangelist_t *ranges)
+CreateJ::StringSet(const apr_array_header_t *strings)
 {
-  JNIEnv *env = JNIUtil::getEnv();
-
-  // Create a local frame for our references
-  env->PushLocalFrame(LOCAL_FRAME_SIZE);
-  if (JNIUtil::isJavaExceptionThrown())
-    return NULL;
-
-  jclass clazz = env->FindClass("java/util/ArrayList");
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
+  std::vector<jobject> jstrs;
 
-  static jmethodID init_mid = 0;
-  if (init_mid == 0)
+  for (int i = 0; i < strings->nelts; ++i)
     {
-      init_mid = env->GetMethodID(clazz, "<init>", "()V");
+      const char *str = APR_ARRAY_IDX(strings, i, const char *);
+      jstring jstr = JNIUtil::makeJString(str);
       if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
-    }
+        return NULL;
 
-  static jmethodID add_mid = 0;
-  if (add_mid == 0)
-    {
-      add_mid = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+      jstrs.push_back(jstr);
     }
 
-  jobject jranges = env->NewObject(clazz, init_mid);
+  return CreateJ::Set(jstrs);
+}
 
-  for (int i = 0; i < ranges->nelts; ++i)
-    {
-      // Convert svn_merge_range_t *'s to Java RevisionRange objects.
-      svn_merge_range_t *range =
-          APR_ARRAY_IDX(ranges, i, svn_merge_range_t *);
+namespace {
+void fill_property_map(jobject map,
+                       apr_hash_t* prop_hash, apr_array_header_t* prop_diffs,
+                       apr_pool_t* scratch_pool, jmethodID put_mid)
+{
+  SVN_ERR_ASSERT_NO_RETURN(!prop_hash != !prop_diffs
+                           || !prop_hash && !prop_diffs);
 
-      jobject jrange = RevisionRange::makeJRevisionRange(range);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+  if (!map || (prop_hash == NULL && prop_diffs == NULL))
+    return;
 
-      env->CallBooleanMethod(jranges, add_mid, jrange);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+  JNIEnv *env = JNIUtil::getEnv();
 
-      env->DeleteLocalRef(jrange);
+  // Create a local frame for our references
+  env->PushLocalFrame(LOCAL_FRAME_SIZE);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  // The caller may not know the concrete class of the map, so
+  // determine the "put" method identifier here.
+  if (put_mid == 0)
+    {
+      put_mid = env->GetMethodID(env->GetObjectClass(map), "put",
+                                 "(Ljava/lang/Object;Ljava/lang/Object;)"
+                                 "Ljava/lang/Object;");
+      if (JNIUtil::isJavaExceptionThrown())
+        POP_AND_RETURN_NOTHING();
     }
 
-  return env->PopLocalFrame(jranges);
-}
+  struct body
+  {
+    void operator()(const char* key, const svn_string_t* val)
+      {
+        jstring jpropName = JNIUtil::makeJString(key);
+        if (JNIUtil::isJavaExceptionThrown())
+          return;
+
+        jbyteArray jpropVal = (!val ? NULL
+                               : JNIUtil::makeJByteArray(val));
+        if (JNIUtil::isJavaExceptionThrown())
+          return;
+
+        m_env->CallObjectMethod(m_map, m_put_mid, jpropName, jpropVal);
+        if (JNIUtil::isJavaExceptionThrown())
+          return;
+
+        m_env->DeleteLocalRef(jpropName);
+        m_env->DeleteLocalRef(jpropVal);
+      }
+
+    JNIEnv*& m_env;
+    jmethodID& m_put_mid;
+    jobject& m_map;
+
+    body(JNIEnv*& xenv, jmethodID& xput_mid, jobject& xmap)
+      : m_env(xenv), m_put_mid(xput_mid), m_map(xmap)
+      {}
+  } loop_body(env, put_mid, map);
+
+  if (prop_hash)
+    {
+      if (!scratch_pool)
+        scratch_pool = apr_hash_pool_get(prop_hash);
+
+      apr_hash_index_t *hi;
+      for (hi = apr_hash_first(scratch_pool, prop_hash);
+           hi; hi = apr_hash_next(hi))
+        {
+          const char* key;
+          svn_string_t* val;
 
-jobject
-CreateJ::StringSet(apr_array_header_t *strings)
-{
-  std::vector<jobject> jstrs;
+          const void* v_key;
+          void* v_val;
 
-  for (int i = 0; i < strings->nelts; ++i)
-    {
-      const char *str = APR_ARRAY_IDX(strings, i, const char *);
-      jstring jstr = JNIUtil::makeJString(str);
-      if (JNIUtil::isJavaExceptionThrown())
-        return NULL;
+          apr_hash_this(hi, &v_key, NULL, &v_val);
+          key = static_cast<const char*>(v_key);
+          val = static_cast<svn_string_t*>(v_val);
 
-      jstrs.push_back(jstr);
+          loop_body(key, val);
+          if (JNIUtil::isJavaExceptionThrown())
+            POP_AND_RETURN_NOTHING();
+        }
+    }
+  else
+    {
+      for (int i = 0; i < prop_diffs->nelts; ++i)
+        {
+          svn_prop_t* prop = APR_ARRAY_IDX(prop_diffs, i, svn_prop_t*);
+          loop_body(prop->name, prop->value);
+          if (JNIUtil::isJavaExceptionThrown())
+            POP_AND_RETURN_NOTHING();
+        }
     }
-
-  return CreateJ::Set(jstrs);
 }
 
-jobject CreateJ::PropertyMap(apr_hash_t *prop_hash)
+jobject property_map(apr_hash_t *prop_hash, apr_array_header_t* prop_diffs,
+                     apr_pool_t* scratch_pool)
 {
-  JNIEnv *env = JNIUtil::getEnv();
+  SVN_ERR_ASSERT_NO_RETURN(!prop_hash != !prop_diffs
+                           || !prop_hash && !prop_diffs);
 
-  if (prop_hash == NULL)
+  if (prop_hash == NULL && prop_diffs == NULL)
     return NULL;
 
+  JNIEnv *env = JNIUtil::getEnv();
+
   // Create a local frame for our references
   env->PushLocalFrame(LOCAL_FRAME_SIZE);
   if (JNIUtil::isJavaExceptionThrown())
@@ -1058,35 +1230,35 @@ jobject CreateJ::PropertyMap(apr_hash_t 
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
-  apr_hash_index_t *hi;
-  for (hi = apr_hash_first(apr_hash_pool_get(prop_hash), prop_hash);
-       hi; hi = apr_hash_next(hi))
-    {
-      const char *key;
-      svn_string_t *val;
-
-      apr_hash_this(hi,
-                    reinterpret_cast<const void **>(&key),
-                    NULL,
-                    reinterpret_cast<void **>(&val));
+  fill_property_map(map, prop_hash, prop_diffs, scratch_pool, put_mid);
+  if (JNIUtil::isJavaExceptionThrown())
+    POP_AND_RETURN_NULL;
 
-      jstring jpropName = JNIUtil::makeJString(key);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+  return env->PopLocalFrame(map);
+}
+} // anonymous namespace
 
-      jbyteArray jpropVal = JNIUtil::makeJByteArray(val);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+jobject CreateJ::PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool)
+{
+  return property_map(prop_hash, NULL, scratch_pool);
+}
 
-      env->CallObjectMethod(map, put_mid, jpropName, jpropVal);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
+jobject CreateJ::PropertyMap(apr_array_header_t* prop_diffs,
+                             apr_pool_t* scratch_pool)
+{
+  return property_map(NULL, prop_diffs, scratch_pool);
+}
 
-      env->DeleteLocalRef(jpropName);
-      env->DeleteLocalRef(jpropVal);
-    }
+void CreateJ::FillPropertyMap(jobject map, apr_hash_t* prop_hash,
+                              apr_pool_t* scratch_pool, jmethodID put_mid)
+{
+  fill_property_map(map, prop_hash, NULL, scratch_pool, put_mid);
+}
 
-  return env->PopLocalFrame(map);
+void CreateJ::FillPropertyMap(jobject map, apr_array_header_t* prop_diffs,
+                              apr_pool_t* scratch_pool, jmethodID put_mid)
+{
+  fill_property_map(map, NULL, prop_diffs, scratch_pool, put_mid);
 }
 
 jobject CreateJ::InheritedProps(apr_array_header_t *iprops)
@@ -1169,6 +1341,64 @@ jobject CreateJ::InheritedProps(apr_arra
   return env->PopLocalFrame(array);
 }
 
+jobject CreateJ::Mergeinfo(svn_mergeinfo_t mergeinfo, apr_pool_t* scratch_pool)
+{
+  if (mergeinfo == NULL)
+    return NULL;
+
+  // Transform mergeinfo into Java Mergeinfo object.
+  JNIEnv *env = JNIUtil::getEnv();
+  jclass clazz = env->FindClass(JAVA_PACKAGE "/types/Mergeinfo");
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  static jmethodID ctor = 0;
+  if (ctor == 0)
+    {
+      ctor = env->GetMethodID(clazz, "<init>", "()V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+    }
+
+  static jmethodID addRevisions = 0;
+  if (addRevisions == 0)
+    {
+      addRevisions = env->GetMethodID(clazz, "addRevisions",
+                                      "(Ljava/lang/String;"
+                                      "Ljava/util/List;)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+    }
+
+  jobject jmergeinfo = env->NewObject(clazz, ctor);
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  apr_hash_index_t *hi;
+  for (hi = apr_hash_first(scratch_pool, mergeinfo);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const void *path;
+      void *val;
+      apr_hash_this(hi, &path, NULL, &val);
+
+      jstring jpath =
+        JNIUtil::makeJString(static_cast<const char*>(path));
+      jobject jranges =
+        RevisionRangeList(static_cast<svn_rangelist_t*>(val)).toList();
+
+      env->CallVoidMethod(jmergeinfo, addRevisions, jpath, jranges);
+
+      env->DeleteLocalRef(jranges);
+      env->DeleteLocalRef(jpath);
+    }
+
+  env->DeleteLocalRef(clazz);
+
+  return jmergeinfo;
+}
+
 
 jobject CreateJ::Set(std::vector<jobject> &objects)
 {

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/CreateJ.h Tue Oct 15 08:52:06 2013
@@ -31,6 +31,7 @@
 #include "svn_wc.h"
 #include "svn_repos.h"
 #include "svn_client.h"
+#include "svn_mergeinfo.h"
 
 #include <vector>
 
@@ -49,12 +50,19 @@ class CreateJ
   Checksum(const svn_checksum_t *checksum);
 
   static jobject
+  DirEntry(const char *path, const char *absPath,
+           const svn_dirent_t *dirent);
+
+  static jobject
   Info(const char *path, const svn_client_info2_t *info);
 
   static jobject
   Lock(const svn_lock_t *lock);
 
   static jobject
+  LockMap(const apr_hash_t *locks, apr_pool_t *pool);
+
+  static jobject
   ChangedPath(const char *path, svn_log_changed_path2_t *log_item);
 
   static jobject
@@ -74,17 +82,30 @@ class CreateJ
   CommitInfo(const svn_commit_info_t *info);
 
   static jobject
-  RevisionRangeList(svn_rangelist_t *ranges);
+  StringSet(const apr_array_header_t *strings);
 
   static jobject
-  StringSet(apr_array_header_t *strings);
+  PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool = NULL);
 
   static jobject
-  PropertyMap(apr_hash_t *prop_hash);
+  PropertyMap(apr_array_header_t* prop_diffs, apr_pool_t* scratch_pool = NULL);
+
+  static void
+  FillPropertyMap(jobject map, apr_hash_t* prop_hash,
+                  apr_pool_t* scratch_pool,
+                  jmethodID put_method_id = 0);
+
+  static void
+  FillPropertyMap(jobject map, apr_array_header_t* prop_diffs,
+                  apr_pool_t* scratch_pool,
+                  jmethodID put_method_id = 0);
 
   static jobject
   InheritedProps(apr_array_header_t *inherited_props);
 
+  static jobject
+  Mergeinfo(svn_mergeinfo_t mergeinfo, apr_pool_t* scratch_pool);
+
   /* This creates a set of Objects.  It derefs the members of the vector
    * after putting them in the set, so they caller doesn't need to. */
   static jobject

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.cpp Tue Oct 15 08:52:06 2013
@@ -191,12 +191,42 @@ int EnumMapper::toLogLevel(jobject jLogL
   return getOrdinal(JAVA_PACKAGE"/SVNClient$ClientLogLevel", jLogLevel);
 }
 
+svn_node_kind_t EnumMapper::toNodeKind(jobject jNodeKind)
+{
+  return svn_node_kind_t(
+      getOrdinal(JAVA_PACKAGE"/types/NodeKind", jNodeKind));
+}
+
+svn_checksum_kind_t EnumMapper::toChecksumKind(jobject jChecksumKind)
+{
+  return svn_checksum_kind_t(
+      getOrdinal(JAVA_PACKAGE"/types/Checksum$Kind", jChecksumKind));
+}
+
+svn_tristate_t EnumMapper::toTristate(jobject jTristate)
+{
+  switch (getOrdinal(JAVA_PACKAGE"/types/Tristate", jTristate))
+    {
+    case 1: return svn_tristate_false;
+    case 2: return svn_tristate_true;
+    default: return svn_tristate_unknown;
+    }
+}
+
 svn_depth_t EnumMapper::toDepth(jobject jdepth)
 {
   // The offset for depths is -2
   return static_cast<svn_depth_t>(getOrdinal(JAVA_PACKAGE"/types/Depth", jdepth) - 2);
 }
 
+svn_mergeinfo_inheritance_t
+EnumMapper::toMergeinfoInheritance(jobject jInheritance)
+{
+  return static_cast<svn_mergeinfo_inheritance_t>(
+      getOrdinal(JAVA_PACKAGE"/types/Mergeinfo$Inheritance", jInheritance));
+}
+
+
 jobject EnumMapper::mapDepth(svn_depth_t depth)
 {
   // We're assuming a valid value for the C enum above

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/EnumMapper.h Tue Oct 15 08:52:06 2013
@@ -48,6 +48,11 @@ class EnumMapper
   static svn_wc_conflict_choice_t toConflictChoice(jobject jchoice);
   static int toMergeinfoLogKind(jobject jLogKind);
   static int toLogLevel(jobject jLogLevel);
+  static svn_node_kind_t toNodeKind(jobject jNodeKind);
+  static svn_checksum_kind_t toChecksumKind(jobject jChecksumKind);
+  static svn_tristate_t toTristate(jobject jTristate);
+  static svn_mergeinfo_inheritance_t
+    toMergeinfoInheritance(jobject jInheritance);
 
   /* Converting from C enum's */
   static jint mapCommitMessageStateFlags(apr_byte_t flags);

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/InfoCallback.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/InfoCallback.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/InfoCallback.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/InfoCallback.h Tue Oct 15 08:52:06 2013
@@ -30,8 +30,6 @@
 #include <jni.h>
 #include "svn_client.h"
 
-struct info_entry;
-
 /**
  * This class holds a Java callback object, which will receive every line of
  * the file for which the callback information is requested.

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.cpp Tue Oct 15 08:52:06 2013
@@ -32,30 +32,24 @@
  * @param flag that the underlying byte array reference should be deleted at
  *        destruction
  */
-JNIByteArray::JNIByteArray(jbyteArray jba, bool deleteByteArray)
-{
-  m_array = jba;
-  m_deleteByteArray = deleteByteArray;
-  if (jba != NULL)
-    {
-      // Get the bytes.
-      JNIEnv *env = JNIUtil::getEnv();
-      m_data = env->GetByteArrayElements(jba, NULL);
-    }
-  else
-    {
-      m_data = NULL;
-    }
-}
+JNIByteArray::JNIByteArray(jbyteArray jba,
+                           bool deleteByteArray,
+                           bool abortOnRelease)
+  : m_array(jba),
+    m_data(!jba ? NULL
+           : JNIUtil::getEnv()->GetByteArrayElements(jba, NULL)),
+    m_deleteByteArray(deleteByteArray),
+    m_abortOnRelease(abortOnRelease)
+{}
 
 JNIByteArray::~JNIByteArray()
 {
   if (m_array != NULL)
     {
       // Release the bytes
-      JNIUtil::getEnv()->ReleaseByteArrayElements(m_array,
-                                                  m_data,
-                                                  JNI_ABORT);
+      JNIUtil::getEnv()->ReleaseByteArrayElements(
+          m_array, m_data,
+          (m_abortOnRelease ? JNI_ABORT: JNI_COMMIT));
       if (m_deleteByteArray)
         // And if needed the byte array.
         JNIUtil::getEnv()->DeleteLocalRef(m_array);

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/JNIByteArray.h Tue Oct 15 08:52:06 2013
@@ -51,11 +51,18 @@ class JNIByteArray
    * at destruction.
    */
   bool m_deleteByteArray;
+
+  /**
+   * False if changes to the array should be committed to the Java VM.
+   */
+  bool m_abortOnRelease;
  public:
   bool isNull() const;
   const signed char *getBytes() const;
   int getLength();
-  JNIByteArray(jbyteArray jba, bool deleteByteArray = false);
+  JNIByteArray(jbyteArray jba,
+               bool deleteByteArray = false,
+               bool abortOnRelease = true);
   ~JNIByteArray();
 };
 

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/JNIStringHolder.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/JNIStringHolder.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/JNIStringHolder.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/JNIStringHolder.h Tue Oct 15 08:52:06 2013
@@ -36,6 +36,7 @@ class JNIStringHolder
   JNIStringHolder(jstring jtext);
   ~JNIStringHolder();
   operator const char *() { return m_str; }
+  const char* c_str() const { return m_str; }
   const char *pstrdup(apr_pool_t *pool);
 
  protected:

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.cpp Tue Oct 15 08:52:06 2013
@@ -24,6 +24,13 @@
  * @brief Implementation of the class JNIUtil
  */
 
+/* Include apr.h first, or INT64_C won't be defined properly on some C99
+   compilers, when other headers include <stdint.h> before defining some
+   macros.
+
+   See apr.h for the ugly details */
+#include <apr.h>
+
 #include "JNIUtil.h"
 #include "Array.h"
 
@@ -35,6 +42,8 @@
 #include <apr_tables.h>
 #include <apr_general.h>
 #include <apr_lib.h>
+#include <apr_file_info.h>
+#include <apr_time.h>
 
 #include "svn_pools.h"
 #include "svn_fs.h"
@@ -44,7 +53,7 @@
 #include "svn_dso.h"
 #include "svn_path.h"
 #include "svn_cache_config.h"
-#include <apr_file_info.h>
+#include "private/svn_atomic.h"
 #include "svn_private_config.h"
 #ifdef WIN32
 /* FIXME: We're using an internal APR header here, which means we
@@ -68,6 +77,7 @@ apr_pool_t *JNIUtil::g_pool = NULL;
 std::list<SVNBase*> JNIUtil::g_finalizedObjects;
 JNIMutex *JNIUtil::g_finalizedObjectsMutex = NULL;
 JNIMutex *JNIUtil::g_logMutex = NULL;
+JNIMutex *JNIUtil::g_configMutex = NULL;
 bool JNIUtil::g_initException;
 bool JNIUtil::g_inInit;
 JNIEnv *JNIUtil::g_initEnv;
@@ -104,6 +114,93 @@ bool JNIUtil::JNIInit(JNIEnv *env)
   return true;
 }
 
+namespace
+{
+struct GlobalInitGuard
+{
+  enum InitState
+    {
+      state_null,
+      state_init,
+      state_done,
+      state_error
+    };
+
+  GlobalInitGuard()
+    : m_finished(false),
+      m_state(InitState(svn_atomic_cas(&m_global_state,
+                                       state_init, state_null)))
+    {
+      switch (m_state)
+        {
+        case state_null:
+          // This thread won the initialization contest.
+          break;
+
+        case state_done:
+          // The library is already initialized.
+          break;
+
+        case state_init:
+          // Another thread is currently initializing the
+          // library. Spin and wait for it to finish, with exponential
+          // backoff, but no longer than half a second.
+          for (unsigned shift = 0;
+               m_state == state_init && shift < 8;
+               ++shift)
+            {
+              apr_sleep((APR_USEC_PER_SEC / 1000) << shift);
+              m_state = InitState(svn_atomic_cas(&m_global_state,
+                                                 state_null, state_null));
+            }
+          if (m_state == state_init)
+            // The initialization didn't complete in half a second,
+            // which probably implies a thread crash or a deadlock.
+            m_state = state_error;
+          break;
+
+        default:
+          // Error state, or unknown state. In any case, do not continue.
+          m_state = state_error;
+        }
+    }
+
+  ~GlobalInitGuard()
+    {
+      // Signal the end of the library intialization if we're the
+      // initializing thread.
+      if (m_finished && m_state == state_null)
+        {
+          SVN_ERR_ASSERT_NO_RETURN(
+              state_init == svn_atomic_cas(&m_global_state,
+                                           state_done, state_init));
+        }
+    }
+
+  bool done() const
+    {
+      return (m_state == state_done);
+    }
+
+  bool error() const
+    {
+      return (m_state == state_error);
+    }
+
+  void finish()
+    {
+      m_finished = true;
+    }
+
+private:
+  bool m_finished;
+  InitState m_state;
+  static volatile svn_atomic_t m_global_state;
+};
+volatile svn_atomic_t
+GlobalInitGuard::m_global_state = GlobalInitGuard::state_null;
+} // anonymous namespace
+
 /**
  * Initialize the environment for all requests.
  * @param env   the JNI environment for this request
@@ -111,27 +208,19 @@ bool JNIUtil::JNIInit(JNIEnv *env)
 bool JNIUtil::JNIGlobalInit(JNIEnv *env)
 {
   // This method has to be run only once during the run a program.
-  static bool run = false;
-  svn_error_t *err;
-  if (run) // already run
+  GlobalInitGuard guard;
+  if (guard.done())
     return true;
-
-  run = true;
-
-  // Do not run this part more than one time.  This leaves a small
-  // time window when two threads create their first SVNClient and
-  // SVNAdmin at the same time, but I do not see a better option
-  // without APR already initialized
-  if (g_inInit)
+  else if (guard.error())
     return false;
 
   g_inInit = true;
   g_initEnv = env;
 
+  svn_error_t *err;
   apr_status_t status;
 
 
-
   /* Initialize the APR subsystem, and register an atexit() function
    * to Uninitialize that subsystem at program exit. */
   status = apr_initialize();
@@ -179,7 +268,7 @@ bool JNIUtil::JNIGlobalInit(JNIEnv *env)
       apr_allocator_max_free_set(allocator, 1);
     }
 
-  svn_utf_initialize2(g_pool, FALSE); /* Optimize character conversions */
+  svn_utf_initialize2(FALSE, g_pool); /* Optimize character conversions */
   svn_fs_initialize(g_pool); /* Avoid some theoretical issues */
   svn_ra_initialize(g_pool);
 
@@ -268,6 +357,10 @@ bool JNIUtil::JNIGlobalInit(JNIEnv *env)
   if (isExceptionThrown())
     return false;
 
+  g_configMutex = new JNIMutex(g_pool);
+  if (isExceptionThrown())
+    return false;
+
   // initialized the thread local storage
   if (!JNIThreadData::initThreadData())
     return false;
@@ -278,6 +371,8 @@ bool JNIUtil::JNIGlobalInit(JNIEnv *env)
 
   g_initEnv = NULL;
   g_inInit = false;
+
+  guard.finish();
   return true;
 }
 
@@ -308,16 +403,6 @@ void JNIUtil::raiseThrowable(const char 
   env->DeleteLocalRef(clazz);
 }
 
-jstring JNIUtil::makeSVNErrorMessage(svn_error_t *err)
-{
-  if (err == NULL)
-    return NULL;
-  std::string buffer;
-  assembleErrorMessage(err, 0, APR_SUCCESS, buffer);
-  jstring jmessage = makeJString(buffer.c_str());
-  return jmessage;
-}
-
 void
 JNIUtil::throwNativeException(const char *className, const char *msg,
                               const char *source, int aprErr)
@@ -418,10 +503,173 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
   env->DeleteLocalRef(jfileName);
 }
 
-void JNIUtil::handleSVNError(svn_error_t *err)
+namespace {
+struct MessageStackItem
+{
+  apr_status_t m_code;
+  std::string m_message;
+  bool m_generic;
+
+  MessageStackItem(apr_status_t code, const char* message,
+                   bool generic = false)
+    : m_code(code),
+      m_message(message),
+      m_generic(generic)
+    {}
+};
+typedef std::vector<MessageStackItem> ErrorMessageStack;
+
+/*
+ * Build the error message from the svn error into buffer.  This
+ * method iterates through all the chained errors
+ *
+ * @param err               the subversion error
+ * @param buffer            the buffer where the formated error message will
+ *                          be stored
+ * @return An array of error codes and messages
+ */
+ErrorMessageStack assemble_error_message(
+    svn_error_t *err, std::string &result)
+{
+  // buffer for a single error message
+  char errbuf[1024];
+  apr_status_t parent_apr_err = 0;
+  ErrorMessageStack message_stack;
+
+  /* Pretty-print the error */
+  /* Note: we can also log errors here someday. */
+
+  for (int depth = 0; err;
+       ++depth, parent_apr_err = err->apr_err, err = err->child)
+    {
+      /* When we're recursing, don't repeat the top-level message if its
+       * 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))
+            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. */
+              apr_strerror(err->apr_err, errbuf, sizeof(errbuf));
+              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);
+                  message = svn_utf_cstring_from_utf8_fuzzy(errbuf, err->pool);
+                }
+            }
+
+          message_stack.push_back(
+              MessageStackItem(err->apr_err, message, true));
+        }
+      if (err->message)
+        {
+          message_stack.push_back(
+              MessageStackItem(err->apr_err, err->message));
+        }
+    }
+
+  for (ErrorMessageStack::const_iterator it = message_stack.begin();
+       it != message_stack.end(); ++it)
+    {
+      if (!it->m_generic)
+        result += "svn: ";
+      result += it->m_message;
+      result += '\n';
+    }
+  return message_stack;
+}
+
+jobject construct_Jmessage_stack(const ErrorMessageStack& message_stack)
 {
-  std::string msg;
-  assembleErrorMessage(svn_error_purge_tracing(err), 0, APR_SUCCESS, msg);
+  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 (ErrorMessageStack::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
+
+std::string JNIUtil::makeSVNErrorMessage(svn_error_t *err,
+                                         jstring *jerror_message,
+                                         jobject *jmessage_stack)
+{
+  if (jerror_message)
+    *jerror_message = NULL;
+  if (jmessage_stack)
+    *jmessage_stack = NULL;
+
+  std::string buffer;
+  err = svn_error_purge_tracing(err);
+  if (err == NULL || err->apr_err == 0
+      || !(jerror_message || jmessage_stack))
+  return buffer;
+
+  ErrorMessageStack message_stack = assemble_error_message(err, buffer);
+  if (jerror_message)
+    *jerror_message = makeJString(buffer.c_str());
+  if (jmessage_stack)
+    *jmessage_stack = construct_Jmessage_stack(message_stack);
+  return buffer;
+}
+
+void JNIUtil::wrappedHandleSVNError(svn_error_t *err)
+{
+  jstring jmessage;
+  jobject jstack;
+  std::string msg = makeSVNErrorMessage(err, &jmessage, &jstack);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
   const char *source = NULL;
 #ifdef SVN_DEBUG
 #ifndef SVN_ERR__TRACING
@@ -465,19 +713,18 @@ void JNIUtil::handleSVNError(svn_error_t
   if (isJavaExceptionThrown())
     POP_AND_RETURN_NOTHING();
 
-  jstring jmessage = makeJString(msg.c_str());
-  if (isJavaExceptionThrown())
-    POP_AND_RETURN_NOTHING();
   jstring jsource = makeJString(source);
   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), jstack);
   if (isJavaExceptionThrown())
     POP_AND_RETURN_NOTHING();
 
@@ -513,7 +760,7 @@ void JNIUtil::handleSVNError(svn_error_t
     POP_AND_RETURN_NOTHING();
 
   const jsize stSize = static_cast<jsize>(newStackTrace.size());
-  if (stSize != newStackTrace.size())
+  if (stSize < 0 || stSize != newStackTrace.size())
     {
       env->ThrowNew(env->FindClass("java.lang.ArithmeticException"),
                     "Overflow converting C size_t to JNI jsize");
@@ -546,7 +793,16 @@ void JNIUtil::handleSVNError(svn_error_t
 #endif
 
   env->Throw(static_cast<jthrowable>(env->PopLocalFrame(nativeException)));
+}
 
+void JNIUtil::handleSVNError(svn_error_t *err)
+{
+  try {
+    wrappedHandleSVNError(err);
+  } catch (...) {
+    svn_error_clear(err);
+    throw;
+  }
   svn_error_clear(err);
 }
 
@@ -643,26 +899,46 @@ bool JNIUtil::isJavaExceptionThrown()
   return false;
 }
 
-const char *
-JNIUtil::thrownExceptionToCString(SVN::Pool &in_pool)
+namespace {
+const char* known_exception_to_cstring(apr_pool_t* pool)
+{
+  JNIEnv *env = JNIUtil::getEnv();
+  jthrowable t = env->ExceptionOccurred();
+  jclass cls = env->GetObjectClass(t);
+
+  jstring jclass_name;
+  {
+    jmethodID mid = env->GetMethodID(cls, "getClass", "()Ljava/lang/Class;");
+    jobject clsobj = env->CallObjectMethod(t, mid);
+    jclass basecls = env->GetObjectClass(clsobj);
+    mid = env->GetMethodID(basecls, "getName", "()Ljava/lang/String;");
+    jclass_name = (jstring) env->CallObjectMethod(clsobj, mid);
+  }
+
+  jstring jmessage;
+  {
+    jmethodID mid = env->GetMethodID(cls, "getMessage",
+                                     "()Ljava/lang/String;");
+    jmessage = (jstring) env->CallObjectMethod(t, mid);
+  }
+
+  JNIStringHolder class_name(jclass_name);
+  if (jmessage)
+    {
+      JNIStringHolder message(jmessage);
+      return apr_pstrcat(pool, class_name.c_str(), ": ", message.c_str(), NULL);
+    }
+  else
+    return class_name.pstrdup(pool);
+  // ### Conditionally add t.printStackTrace() to msg?
+}
+
+const char* exception_to_cstring(apr_pool_t* pool)
 {
   const char *msg;
-  JNIEnv *env = getEnv();
-  if (env->ExceptionCheck())
+  if (JNIUtil::getEnv()->ExceptionCheck())
     {
-      jthrowable t = env->ExceptionOccurred();
-      static jmethodID getMessage = 0;
-      if (getMessage == 0)
-        {
-          jclass clazz = env->FindClass("java/lang/Throwable");
-          getMessage = env->GetMethodID(clazz, "getMessage",
-                                        "(V)Ljava/lang/String;");
-          env->DeleteLocalRef(clazz);
-        }
-      jstring jmsg = (jstring) env->CallObjectMethod(t, getMessage);
-      JNIStringHolder tmp(jmsg);
-      msg = tmp.pstrdup(in_pool.getPool());
-      // ### Conditionally add t.printStackTrace() to msg?
+      msg = known_exception_to_cstring(pool);
     }
   else
     {
@@ -670,6 +946,27 @@ JNIUtil::thrownExceptionToCString(SVN::P
     }
   return msg;
 }
+} // anonymous namespace
+
+const char *
+JNIUtil::thrownExceptionToCString(SVN::Pool &in_pool)
+{
+  return exception_to_cstring(in_pool.getPool());
+}
+
+svn_error_t*
+JNIUtil::checkJavaException(apr_status_t errorcode)
+{
+  if (!getEnv()->ExceptionCheck())
+    return SVN_NO_ERROR;
+  svn_error_t* err = svn_error_create(errorcode, NULL, NULL);
+  const char* const msg = known_exception_to_cstring(err->pool);
+  if (msg)
+    err->message = apr_psprintf(err->pool, _("Java exception: %s"), msg);
+  else
+    err->message = _("Java exception");
+  return err;
+}
 
 /**
  * Create a Java string from a native UTF-8 string.
@@ -796,6 +1093,31 @@ jobject JNIUtil::createDate(apr_time_t t
   return ret;
 }
 
+apr_time_t
+JNIUtil::getDate(jobject jdate)
+{
+  JNIEnv *env = getEnv();
+  jclass clazz = env->FindClass("java/util/Date");
+  if (isJavaExceptionThrown())
+    return 0;
+
+  static jmethodID mid = 0;
+  if (mid == 0)
+    {
+      mid = env->GetMethodID(clazz, "getTime", "()J");
+      if (isJavaExceptionThrown())
+        return 0;
+    }
+
+  jlong jmillis = env->CallLongMethod(jdate, mid);
+  if (isJavaExceptionThrown())
+    return 0;
+
+  env->DeleteLocalRef(clazz);
+
+  return jmillis * 1000;
+}
+
 /**
  * Create a Java byte array from an array of characters.
  * @param data      the character array
@@ -803,11 +1125,9 @@ jobject JNIUtil::createDate(apr_time_t t
  */
 jbyteArray JNIUtil::makeJByteArray(const void *data, int length)
 {
-  if (data == NULL)
-    {
-      // a NULL will create no Java array
-      return NULL;
-    }
+  // a NULL will create no Java array
+  if (!data)
+    return NULL;
 
   JNIEnv *env = getEnv();
 
@@ -838,48 +1158,11 @@ jbyteArray JNIUtil::makeJByteArray(const
  */
 jbyteArray JNIUtil::makeJByteArray(const svn_string_t *str)
 {
-  return JNIUtil::makeJByteArray(str->data, static_cast<int>(str->len));
-}
-
-/**
- * Build the error message from the svn error into buffer.  This
- * method calls itselft recursively for all the chained errors
- *
- * @param err               the subversion error
- * @param depth             the depth of the call, used for formating
- * @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
- */
-void JNIUtil::assembleErrorMessage(svn_error_t *err, int depth,
-                                   apr_status_t parent_apr_err,
-                                   std::string &buffer)
-{
-  // buffer for a single error message
-  char errbuf[256];
-
-  /* Pretty-print the error */
-  /* Note: we can also log errors here someday. */
-
-  /* When we're recursing, don't repeat the top-level message if its
-   * the same as before. */
-  if (depth == 0 || err->apr_err != parent_apr_err)
-    {
-      /* 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)));
-      /* Otherwise, this must be an APR error code. */
-      else
-        buffer.append(apr_strerror(err->apr_err, errbuf, sizeof(errbuf)));
-      buffer.append("\n");
-    }
-  if (err->message)
-    buffer.append(_("svn: ")).append(err->message).append("\n");
-
-  if (err->child)
-    assembleErrorMessage(err->child, depth + 1, err->apr_err, buffer);
+  // a NULL will create no Java array
+  if (!str)
+    return NULL;
 
+  return JNIUtil::makeJByteArray(str->data, static_cast<int>(str->len));
 }
 
 /**

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/JNIUtil.h Tue Oct 15 08:52:06 2013
@@ -37,8 +37,11 @@ class SVNBase;
 #include <fstream>
 #include <apr_time.h>
 #include <string>
+#include <vector>
 struct svn_error_t;
 
+#include "svn_error.h"
+
 #define JAVA_PACKAGE "org/apache/subversion/javahl"
 
 struct svn_string_t;
@@ -67,6 +70,7 @@ class JNIUtil
   static jbyteArray makeJByteArray(const void *data, int length);
   static jbyteArray makeJByteArray(const svn_string_t *str);
   static jobject createDate(apr_time_t time);
+  static apr_time_t getDate(jobject jdate);
   static void logMessage(const char *message);
   static int getLogLevel();
   static char *getFormatBuffer();
@@ -107,12 +111,20 @@ class JNIUtil
   static const char *thrownExceptionToCString(SVN::Pool &in_pool);
 
   /**
+   * Check if a Java exception was thrown and convert it to a
+   * Subversion error, using @a errorcode as the generic error code.
+   */
+  static svn_error_t* checkJavaException(apr_status_t errorcode);
+
+  /**
    * Throw a Java exception corresponding to err, and run
    * svn_error_clear() on err.
    */
   static void handleSVNError(svn_error_t *err);
 
-  static jstring makeSVNErrorMessage(svn_error_t *err);
+  static std::string makeSVNErrorMessage(svn_error_t *err,
+                                         jstring *jerror_message,
+                                         jobject *jmessage_stack);
 
   /**
    * Create and throw a java.lang.Throwable instance.
@@ -140,10 +152,13 @@ class JNIUtil
   enum { formatBufferSize = 2048 };
   enum { noLog, errorLog, exceptionLog, entryLog } LogLevel;
 
+  /**
+   * Mutex that secures the global configuration object.
+   */
+  static JNIMutex *g_configMutex;
+
  private:
-  static void assembleErrorMessage(svn_error_t *err, int depth,
-                                   apr_status_t parent_apr_err,
-                                   std::string &buffer);
+  static void wrappedHandleSVNError(svn_error_t *err);
   static void putErrorsInTrace(svn_error_t *err,
                                std::vector<jobject> &stackTrace);
   /**
@@ -283,4 +298,10 @@ class JNIUtil
     }                                                   \
   } while (0)
 
+#define SVN_JNI_CATCH(statement, errorcode)             \
+  do {                                                  \
+    do { statement; } while(0);                         \
+    SVN_ERR(JNIUtil::checkJavaException((errorcode)));  \
+  } while(0)
+
 #endif  // JNIUTIL_H

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/ListCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/ListCallback.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/ListCallback.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/ListCallback.cpp Tue Oct 15 08:52:06 2013
@@ -126,53 +126,5 @@ jobject
 ListCallback::createJavaDirEntry(const char *path, const char *absPath,
                                  const svn_dirent_t *dirent)
 {
-  JNIEnv *env = JNIUtil::getEnv();
-
-  // Create a local frame for our references
-  env->PushLocalFrame(LOCAL_FRAME_SIZE);
-  if (JNIUtil::isJavaExceptionThrown())
-    return SVN_NO_ERROR;
-
-  jclass clazz = env->FindClass(JAVA_PACKAGE"/types/DirEntry");
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  static jmethodID mid = 0;
-  if (mid == 0)
-    {
-      mid = env->GetMethodID(clazz, "<init>",
-                             "(Ljava/lang/String;Ljava/lang/String;"
-                             "L"JAVA_PACKAGE"/types/NodeKind;"
-                             "JZJJLjava/lang/String;)V");
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NULL;
-    }
-
-  jstring jPath = JNIUtil::makeJString(path);
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  jstring jAbsPath = JNIUtil::makeJString(absPath);
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  jobject jNodeKind = EnumMapper::mapNodeKind(dirent->kind);
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  jlong jSize = dirent->size;
-  jboolean jHasProps = (dirent->has_props? JNI_TRUE : JNI_FALSE);
-  jlong jLastChangedRevision = dirent->created_rev;
-  jlong jLastChanged = dirent->time;
-  jstring jLastAuthor = JNIUtil::makeJString(dirent->last_author);
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  jobject ret = env->NewObject(clazz, mid, jPath, jAbsPath, jNodeKind,
-                               jSize, jHasProps, jLastChangedRevision,
-                               jLastChanged, jLastAuthor);
-  if (JNIUtil::isJavaExceptionThrown())
-    POP_AND_RETURN_NULL;
-
-  return env->PopLocalFrame(ret);
+  return CreateJ::DirEntry(path, absPath, dirent);
 }

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/LogMessageCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/LogMessageCallback.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/LogMessageCallback.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/LogMessageCallback.cpp Tue Oct 15 08:52:06 2013
@@ -117,7 +117,7 @@ LogMessageCallback::singleMessage(svn_lo
 
   jobject jrevprops = NULL;
   if (log_entry->revprops != NULL && apr_hash_count(log_entry->revprops) > 0)
-    jrevprops = CreateJ::PropertyMap(log_entry->revprops);
+    jrevprops = CreateJ::PropertyMap(log_entry->revprops, pool);
 
   env->CallVoidMethod(m_callback,
                       sm_mid,

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/PatchCallback.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/PatchCallback.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/PatchCallback.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/PatchCallback.h Tue Oct 15 08:52:06 2013
@@ -30,8 +30,6 @@
 #include <jni.h>
 #include "svn_client.h"
 
-struct info_entry;
-
 /**
  * This class holds a Java callback object, which will receive every line of
  * the file for which the callback information is requested.

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/Path.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/Path.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/Path.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/Path.cpp Tue Oct 15 08:52:06 2013
@@ -27,18 +27,24 @@
 #include <jni.h>
 #include "Path.h"
 #include "svn_path.h"
+#include "svn_dirent_uri.h"
 #include "JNIUtil.h"
+#include "JNIStringHolder.h"
 #include "Pool.h"
+#include "svn_private_config.h"
 
 /**
  * Constructor
  *
- * @see Path::Path(const std::string &)
+ * @see PathBase::PathBase(const std::string &)
  * @param path Path string
  */
-Path::Path(const char *pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(const char *pi_path,
+                   svn_error_t* initfunc(const char*&, SVN::Pool&),
+                   SVN::Pool &in_pool)
+  : m_error_occurred(NULL)
 {
-  init(pi_path, in_pool);
+  init(pi_path, initfunc, in_pool);
 }
 
 /**
@@ -48,19 +54,26 @@ Path::Path(const char *pi_path, SVN::Poo
  *
  * @param path Path string
  */
-Path::Path(const std::string &pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(const std::string &pi_path,
+                   svn_error_t* initfunc(const char*&, SVN::Pool&),
+                   SVN::Pool &in_pool)
+  : m_error_occurred(NULL)
 {
-  init(pi_path.c_str(), in_pool);
+  init(pi_path.c_str(), initfunc, in_pool);
 }
 
 /**
- * Copy constructor
- *
- * @param path Path to be copied
+ * Constructor from a Java string.
  */
-Path::Path(const Path &pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(jstring jpath,
+                   svn_error_t* initfunc(const char*&, SVN::Pool&),
+                   SVN::Pool &in_pool)
+  : m_error_occurred(NULL)
 {
-  init(pi_path.c_str(), in_pool);
+  JNIStringHolder path(jpath);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+  init(path, initfunc, in_pool);
 }
 
 /**
@@ -69,17 +82,13 @@ Path::Path(const Path &pi_path, SVN::Poo
  * @param path Path string
  */
 void
-Path::init(const char *pi_path, SVN::Pool &in_pool)
+PathBase::init(const char *pi_path,
+               svn_error_t* initfunc(const char*&, SVN::Pool&),
+               SVN::Pool &in_pool)
 {
-  if (*pi_path == 0)
-    {
-      m_error_occurred = NULL;
-      m_path = "";
-    }
-  else
+  if (pi_path && *pi_path)
     {
-      m_error_occurred = JNIUtil::preprocessPath(pi_path, in_pool.getPool());
-
+      m_error_occurred = initfunc(pi_path, in_pool);
       m_path = pi_path;
     }
 }
@@ -88,7 +97,7 @@ Path::init(const char *pi_path, SVN::Poo
  * @return Path string
  */
 const std::string &
-Path::path() const
+PathBase::path() const
 {
   return m_path;
 }
@@ -97,7 +106,7 @@ Path::path() const
  * @return Path string as a C string
  */
 const char *
-Path::c_str() const
+PathBase::c_str() const
 {
   return m_path.c_str();
 }
@@ -105,8 +114,8 @@ Path::c_str() const
 /**
  * Assignment operator
  */
-Path&
-Path::operator=(const Path &pi_path)
+PathBase&
+PathBase::operator=(const PathBase &pi_path)
 {
   m_error_occurred = NULL;
   m_path = pi_path.m_path;
@@ -114,12 +123,12 @@ Path::operator=(const Path &pi_path)
   return *this;
 }
 
-  svn_error_t *Path::error_occurred() const
+svn_error_t *PathBase::error_occurred() const
 {
   return m_error_occurred;
 }
 
-jboolean Path::isValid(const char *p)
+jboolean PathBase::isValid(const char *p)
 {
   if (p == NULL)
     return JNI_FALSE;
@@ -136,3 +145,25 @@ jboolean Path::isValid(const char *p)
       return JNI_FALSE;
     }
 }
+
+svn_error_t*
+Path::initfunc(const char*& path, SVN::Pool& pool)
+{
+  return JNIUtil::preprocessPath(path, pool.getPool());
+}
+
+svn_error_t*
+URL::initfunc(const char*& path, SVN::Pool& pool)
+{
+  if (svn_path_is_url(path))
+    return JNIUtil::preprocessPath(path, pool.getPool());
+  return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                           _("Not an URL: %s"), path);
+}
+
+svn_error_t*
+Relpath::initfunc(const char*& path, SVN::Pool& pool)
+{
+  path = svn_relpath__internal_style(path, pool.getPool());
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/Path.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/Path.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/Path.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/Path.h Tue Oct 15 08:52:06 2013
@@ -24,18 +24,19 @@
  * @brief Interface of the C++ class Path.
  */
 
-#ifndef PATH_H
-#define PATH_H
+#ifndef JAVAHL_PATH_H
+#define JAVAHL_PATH_H
 
 #include <string>
 #include <jni.h>
 #include "Pool.h"
 struct svn_error_t;
 
+
 /**
  * Encapsulation for Subversion Path handling
  */
-class Path
+class PathBase
 {
  private:
   // The path to be stored.
@@ -48,9 +49,11 @@ class Path
    *
    * @param pi_path Path string
    */
-  void init(const char *pi_path, SVN::Pool &in_pool);
+  void init(const char *pi_path,
+            svn_error_t* initfunc(const char*&, SVN::Pool&),
+            SVN::Pool &in_pool);
 
- public:
+ protected:
   /**
    * Constructor that takes a string as parameter.
    * The string is converted to subversion internal
@@ -58,27 +61,31 @@ class Path
    *
    * @param pi_path Path string
    */
-  Path(const std::string &pi_path, SVN::Pool &in_pool);
+  PathBase(const std::string &pi_path,
+           svn_error_t* initfunc(const char*&, SVN::Pool&),
+           SVN::Pool &in_pool);
 
   /**
    * Constructor
    *
-   * @see Path::Path (const std::string &)
+   * @see PathBase::PathBase (const std::string &)
    * @param pi_path Path string
    */
-  Path(const char *pi_path, SVN::Pool &in_pool);
+  PathBase(const char *pi_path,
+           svn_error_t* initfunc(const char*&, SVN::Pool&),
+           SVN::Pool &in_pool);
 
   /**
-   * Copy constructor
-   *
-   * @param pi_path Path to be copied
+   * Constructor from a Java string.
    */
-  Path(const Path &pi_path, SVN::Pool &in_pool);
+  PathBase(jstring jpath,
+           svn_error_t* initfunc(const char*&, SVN::Pool&),
+           SVN::Pool &in_pool);
 
   /**
    * Assignment operator
    */
-  Path &operator=(const Path&);
+  PathBase &operator=(const PathBase&);
 
   /**
    * @return Path string
@@ -92,6 +99,7 @@ class Path
 
   svn_error_t *error_occurred() const;
 
+public:
   /**
    * Returns whether @a path is non-NULL and passes the @c
    * svn_path_check_valid() test.
@@ -101,4 +109,113 @@ class Path
   static jboolean isValid(const char *path);
 };
 
-#endif  // PATH_H
+
+/**
+ * Dirent or URI
+ */
+class Path : protected PathBase
+{
+ public:
+  Path(const std::string &pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  Path(const char *pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  Path(jstring jpath, SVN::Pool &in_pool)
+    : PathBase(jpath, initfunc, in_pool)
+    {}
+
+  Path& operator=(const Path& that)
+    {
+      PathBase::operator=(that);
+      return *this;
+    }
+
+  const std::string &path() const { return PathBase::path(); }
+  const char *c_str() const { return PathBase::c_str(); }
+
+  svn_error_t *error_occurred() const
+    {
+      return PathBase::error_occurred();
+    }
+
+ private:
+  static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+/**
+ * URL
+ */
+class URL : protected PathBase
+{
+ public:
+  URL(const std::string &pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  URL(const char *pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  URL(jstring jpath, SVN::Pool &in_pool)
+    : PathBase(jpath, initfunc, in_pool)
+    {}
+
+  URL& operator=(const URL& that)
+    {
+      PathBase::operator=(that);
+      return *this;
+    }
+
+  const std::string &path() const { return PathBase::path(); }
+  const char *c_str() const { return PathBase::c_str(); }
+
+  svn_error_t *error_occurred() const
+    {
+      return PathBase::error_occurred();
+    }
+
+ private:
+  static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+/**
+ * Relative path
+ */
+class Relpath : protected PathBase
+{
+ public:
+  Relpath(const std::string &pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  Relpath(const char *pi_path, SVN::Pool &in_pool)
+    : PathBase(pi_path, initfunc, in_pool)
+    {}
+
+  Relpath(jstring jpath, SVN::Pool &in_pool)
+    : PathBase(jpath, initfunc, in_pool)
+    {}
+
+  Relpath& operator=(const Relpath& that)
+    {
+      PathBase::operator=(that);
+      return *this;
+    }
+
+  const std::string &path() const { return PathBase::path(); }
+  const char *c_str() const { return PathBase::c_str(); }
+
+  svn_error_t *error_occurred() const
+    {
+      return PathBase::error_occurred();
+    }
+
+ private:
+  static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+#endif  // JAVAHL_PATH_H

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/Prompter.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/Prompter.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/Prompter.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/Prompter.cpp Tue Oct 15 08:52:06 2013
@@ -40,9 +40,9 @@
  * @param jprompter     a global reference to the Java callback object
  */
 Prompter::Prompter(jobject jprompter)
-{
-  m_prompter = jprompter;
-}
+  : m_prompter(jprompter),
+    m_maySave(false)
+{}
 
 Prompter::~Prompter()
 {

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/ProplistCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/ProplistCallback.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/ProplistCallback.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/ProplistCallback.cpp Tue Oct 15 08:52:06 2013
@@ -104,7 +104,7 @@ svn_error_t *ProplistCallback::singlePat
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
-  jobject jmap = CreateJ::PropertyMap(prop_hash);
+  jobject jmap = CreateJ::PropertyMap(prop_hash, pool);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
@@ -159,7 +159,7 @@ svn_error_t *ProplistCallback::singlePat
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
-  jobject jmap = CreateJ::PropertyMap(prop_hash);
+  jobject jmap = CreateJ::PropertyMap(prop_hash, pool);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.cpp Tue Oct 15 08:52:06 2013
@@ -44,60 +44,117 @@ RevisionRange::~RevisionRange()
     // explicitly destroyed.
 }
 
-const svn_opt_revision_range_t *RevisionRange::toRange(SVN::Pool &pool) const
+namespace {
+void get_range_info(jobject jrange,
+                    svn_opt_revision_t* range_start,
+                    svn_opt_revision_t* range_end,
+                    svn_boolean_t* range_inheritable)
 {
   JNIEnv *env = JNIUtil::getEnv();
 
   jclass clazz = env->FindClass(JAVA_PACKAGE"/types/RevisionRange");
   if (JNIUtil::isExceptionThrown())
-    return NULL;
+    return;
 
-  static jmethodID fmid = 0;
-  if (fmid == 0)
+  if (range_start)
     {
-      fmid = env->GetMethodID(clazz, "getFromRevision",
-                              "()L"JAVA_PACKAGE"/types/Revision;");
-      if (JNIUtil::isJavaExceptionThrown())
-        return NULL;
+
+      static jmethodID fmid = 0;
+      if (fmid == 0)
+        {
+          fmid = env->GetMethodID(clazz, "getFromRevision",
+                                  "()L"JAVA_PACKAGE"/types/Revision;");
+          if (JNIUtil::isJavaExceptionThrown())
+            return;
+        }
+
+      jobject jstartRevision = env->CallObjectMethod(jrange, fmid);
+      if (JNIUtil::isExceptionThrown())
+        return;
+
+      Revision startRevision(jstartRevision);
+      if (JNIUtil::isExceptionThrown())
+        return;
+
+      *range_start = *startRevision.revision();
+      if (JNIUtil::isExceptionThrown())
+        return;
     }
 
-  static jmethodID tmid = 0;
-  if (tmid == 0)
+  if (range_end)
     {
-      tmid = env->GetMethodID(clazz, "getToRevision",
-                              "()L"JAVA_PACKAGE"/types/Revision;");
-      if (JNIUtil::isJavaExceptionThrown())
-        return NULL;
+      static jmethodID tmid = 0;
+      if (tmid == 0)
+        {
+          tmid = env->GetMethodID(clazz, "getToRevision",
+                                  "()L"JAVA_PACKAGE"/types/Revision;");
+          if (JNIUtil::isJavaExceptionThrown())
+            return;
+        }
+
+      jobject jendRevision = env->CallObjectMethod(jrange, tmid);
+      if (JNIUtil::isExceptionThrown())
+        return;
+
+      Revision endRevision(jendRevision);
+      if (JNIUtil::isExceptionThrown())
+        return;
+
+      *range_end = *endRevision.revision();
+      if (JNIUtil::isExceptionThrown())
+        return;
     }
 
-  jobject jstartRevision = env->CallObjectMethod(m_range, fmid);
-  if (JNIUtil::isExceptionThrown())
-    return NULL;
+  if (range_inheritable)
+    {
+      static jmethodID imid = 0;
+      if (imid == 0 && range_inheritable)
+        {
+          imid = env->GetMethodID(clazz, "isInheritable", "()Z");
+          if (JNIUtil::isJavaExceptionThrown())
+            return;
+        }
+
+      jboolean inheritable = env->CallBooleanMethod(jrange, imid);
+      if (JNIUtil::isExceptionThrown())
+        return;
+      *range_inheritable = inheritable;
+    }
+}
+} // anonymous namespace
 
-  Revision startRevision(jstartRevision);
+svn_merge_range_t* RevisionRange::toMergeRange(SVN::Pool &pool) const
+{
+  svn_opt_revision_t range_start, range_end;
+  svn_boolean_t range_inheritable;
+  get_range_info(m_range, &range_start, &range_end, &range_inheritable);
   if (JNIUtil::isExceptionThrown())
     return NULL;
 
-  jobject jendRevision = env->CallObjectMethod(m_range, tmid);
-  if (JNIUtil::isExceptionThrown())
-    return NULL;
+  if (range_start.kind != svn_opt_revision_number
+      || range_end.kind != svn_opt_revision_number)
+    JNIUtil::raiseThrowable("java.lang.InvalidStateException",
+                            "Revsision ranges must contain revision numbers");
 
-  Revision endRevision(jendRevision);
-  if (JNIUtil::isExceptionThrown())
-    return NULL;
+  svn_merge_range_t* range =
+    static_cast<svn_merge_range_t*>
+      (apr_palloc(pool.getPool(), sizeof(*range)));
+
+  range->start = range_start.value.number;
+  range->end = range_end.value.number;
+  range->inheritable = range_inheritable;
+  return range;
+}
 
+svn_opt_revision_range_t *RevisionRange::toRange(SVN::Pool &pool) const
+{
   svn_opt_revision_range_t *range =
-    reinterpret_cast<svn_opt_revision_range_t *>
+    static_cast<svn_opt_revision_range_t *>
       (apr_palloc(pool.getPool(), sizeof(*range)));
 
-  range->start = *startRevision.revision();
-  if (JNIUtil::isExceptionThrown())
-    return NULL;
-
-  range->end = *endRevision.revision();
+  get_range_info(m_range, &range->start, &range->end, NULL);
   if (JNIUtil::isExceptionThrown())
-    return NULL;
-
+    range = NULL;
   return range;
 }
 
@@ -112,13 +169,14 @@ RevisionRange::makeJRevisionRange(svn_me
     static jmethodID rangeCtor = 0;
     if (rangeCtor == 0)
     {
-        rangeCtor = env->GetMethodID(rangeClazz, "<init>", "(JJ)V");
+        rangeCtor = env->GetMethodID(rangeClazz, "<init>", "(JJZ)V");
         if (JNIUtil::isJavaExceptionThrown())
             return NULL;
     }
     jobject jrange = env->NewObject(rangeClazz, rangeCtor,
-                                    (jlong) range->start,
-                                    (jlong) range->end);
+                                    jlong(range->start),
+                                    jlong(range->end),
+                                    jboolean(range->inheritable));
     if (JNIUtil::isJavaExceptionThrown())
         return NULL;
 

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/RevisionRange.h Tue Oct 15 08:52:06 2013
@@ -29,6 +29,7 @@
 
 #include <jni.h>
 #include "svn_types.h"
+#include "svn_opt.h"
 
 #include "Pool.h"
 
@@ -53,7 +54,12 @@ class RevisionRange
   /**
    * Return an svn_opt_revision_range_t.
    */
-  const svn_opt_revision_range_t *toRange(SVN::Pool &pool) const;
+  svn_opt_revision_range_t *toRange(SVN::Pool &pool) const;
+
+  /**
+   * Return an svn_merge_range_t.
+   */
+  svn_merge_range_t* toMergeRange(SVN::Pool &pool) const;
 
   /**
    * Make a (single) RevisionRange Java object.

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.cpp Tue Oct 15 08:52:06 2013
@@ -97,3 +97,29 @@ inline void SVNBase::findCppAddrFieldID(
         }
     }
 }
+
+jobject SVNBase::createCppBoundObject(const char *clazzName)
+{
+  JNIEnv *env = JNIUtil::getEnv();
+
+  // Create java session object
+  jclass clazz = env->FindClass(clazzName);
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  static jmethodID ctor = 0;
+  if (ctor == 0)
+    {
+      ctor = env->GetMethodID(clazz, "<init>", "(J)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return NULL;
+    }
+
+  jlong cppAddr = this->getCppAddr();
+
+  jobject jself = env->NewObject(clazz, ctor, cppAddr);
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  return jself;
+}

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.h
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.h?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.h (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/SVNBase.h Tue Oct 15 08:52:06 2013
@@ -82,6 +82,11 @@ class SVNBase
    */
   void dispose(jobject jthis, jfieldID *fid, const char *className);
 
+  /**
+   * Instantiates java object attached to this base object
+   */
+  jobject createCppBoundObject(const char *clazzName);
+
  private:
   /**
    * If the value pointed to by @a fid is zero, find the @c jfieldID

Modified: subversion/branches/cache-server/subversion/bindings/javahl/native/SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/bindings/javahl/native/SVNClient.cpp?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/bindings/javahl/native/SVNClient.cpp (original)
+++ subversion/branches/cache-server/subversion/bindings/javahl/native/SVNClient.cpp Tue Oct 15 08:52:06 2013
@@ -30,6 +30,7 @@
 #include "DiffSummaryReceiver.h"
 #include "ClientContext.h"
 #include "Prompter.h"
+#include "RemoteSession.h"
 #include "Pool.h"
 #include "Targets.h"
 #include "Revision.h"
@@ -50,7 +51,7 @@
 #include "CommitMessage.h"
 #include "EnumMapper.h"
 #include "StringArray.h"
-#include "RevpropTable.h"
+#include "PropertyTable.h"
 #include "DiffOptions.h"
 #include "CreateJ.h"
 #include "svn_auth.h"
@@ -70,6 +71,7 @@
 #include <vector>
 #include <iostream>
 #include <sstream>
+#include <string>
 
 
 SVNClient::SVNClient(jobject jthis_in)
@@ -227,23 +229,23 @@ rev_range_vector_to_apr_array(std::vecto
     std::vector<RevisionRange>::const_iterator it;
     for (it = revRanges.begin(); it != revRanges.end(); ++it)
     {
-        if (it->toRange(subPool)->start.kind
-            == svn_opt_revision_unspecified
-            && it->toRange(subPool)->end.kind
-            == svn_opt_revision_unspecified)
+        const svn_opt_revision_range_t *range = it->toRange(subPool);
+
+        if (range->start.kind == svn_opt_revision_unspecified
+            && range->end.kind == svn_opt_revision_unspecified)
         {
-            svn_opt_revision_range_t *range =
+            svn_opt_revision_range_t *full =
                 reinterpret_cast<svn_opt_revision_range_t *>
                     (apr_pcalloc(subPool.getPool(), sizeof(*range)));
-            range->start.kind = svn_opt_revision_number;
-            range->start.value.number = 1;
-            range->end.kind = svn_opt_revision_head;
-            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = range;
+            full->start.kind = svn_opt_revision_number;
+            full->start.value.number = 1;
+            full->end.kind = svn_opt_revision_head;
+            full->end.value.number = 0;
+            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = full;
         }
         else
         {
-            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) =
-                it->toRange(subPool);
+            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = range;
         }
         if (JNIUtil::isExceptionThrown())
             return NULL;
@@ -317,7 +319,7 @@ jlong SVNClient::checkout(const char *mo
 }
 
 void SVNClient::remove(Targets &targets, CommitMessage *message, bool force,
-                       bool keep_local, RevpropTable &revprops,
+                       bool keep_local, PropertyTable &revprops,
                        CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
@@ -417,7 +419,7 @@ jlongArray SVNClient::update(Targets &ta
 
 void SVNClient::commit(Targets &targets, CommitMessage *message,
                        svn_depth_t depth, bool noUnlock, bool keepChangelist,
-                       StringArray &changelists, RevpropTable &revprops,
+                       StringArray &changelists, PropertyTable &revprops,
                        CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
@@ -442,7 +444,7 @@ void SVNClient::commit(Targets &targets,
 void SVNClient::copy(CopySources &copySources, const char *destPath,
                      CommitMessage *message, bool copyAsChild,
                      bool makeParents, bool ignoreExternals,
-                     RevpropTable &revprops, CommitCallback *callback)
+                     PropertyTable &revprops, CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
 
@@ -471,7 +473,7 @@ void SVNClient::copy(CopySources &copySo
 void SVNClient::move(Targets &srcPaths, const char *destPath,
                      CommitMessage *message, bool force, bool moveAsChild,
                      bool makeParents, bool metadataOnly, bool allowMixRev,
-                     RevpropTable &revprops, CommitCallback *callback)
+                     PropertyTable &revprops, CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
 
@@ -496,7 +498,7 @@ void SVNClient::move(Targets &srcPaths, 
 }
 
 void SVNClient::mkdir(Targets &targets, CommitMessage *message,
-                      bool makeParents, RevpropTable &revprops,
+                      bool makeParents, PropertyTable &revprops,
                       CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
@@ -545,6 +547,7 @@ void SVNClient::resolve(const char *path
 jlong SVNClient::doExport(const char *srcPath, const char *destPath,
                           Revision &revision, Revision &pegRevision,
                           bool force, bool ignoreExternals,
+                          bool ignoreKeywords,
                           svn_depth_t depth, const char *nativeEOL)
 {
     SVN::Pool subPool(pool);
@@ -563,7 +566,7 @@ jlong SVNClient::doExport(const char *sr
                                    destinationPath.c_str(),
                                    pegRevision.revision(),
                                    revision.revision(), force,
-                                   ignoreExternals, FALSE,
+                                   ignoreExternals, ignoreKeywords,
                                    depth,
                                    nativeEOL, ctx,
                                    subPool.getPool()),
@@ -613,7 +616,7 @@ void SVNClient::doImport(const char *pat
                          CommitMessage *message, svn_depth_t depth,
                          bool noIgnore, bool noAutoProps,
                          bool ignoreUnknownNodeTypes,
-                         RevpropTable &revprops,
+                         PropertyTable &revprops,
                          ImportFilterCallback *ifCallback,
                          CommitCallback *commitCallback)
 {
@@ -749,8 +752,6 @@ jobject
 SVNClient::getMergeinfo(const char *target, Revision &pegRevision)
 {
     SVN::Pool subPool(pool);
-    JNIEnv *env = JNIUtil::getEnv();
-
     svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
     if (ctx == NULL)
         return NULL;
@@ -765,57 +766,7 @@ SVNClient::getMergeinfo(const char *targ
                 NULL);
     if (mergeinfo == NULL)
         return NULL;
-
-    // Transform mergeinfo into Java Mergeinfo object.
-    jclass clazz = env->FindClass(JAVA_PACKAGE "/types/Mergeinfo");
-    if (JNIUtil::isJavaExceptionThrown())
-        return NULL;
-
-    static jmethodID ctor = 0;
-    if (ctor == 0)
-    {
-        ctor = env->GetMethodID(clazz, "<init>", "()V");
-        if (JNIUtil::isJavaExceptionThrown())
-            return NULL;
-    }
-
-    static jmethodID addRevisions = 0;
-    if (addRevisions == 0)
-    {
-        addRevisions = env->GetMethodID(clazz, "addRevisions",
-                                        "(Ljava/lang/String;"
-                                        "Ljava/util/List;)V");
-        if (JNIUtil::isJavaExceptionThrown())
-            return NULL;
-    }
-
-    jobject jmergeinfo = env->NewObject(clazz, ctor);
-    if (JNIUtil::isJavaExceptionThrown())
-        return NULL;
-
-    apr_hash_index_t *hi;
-    for (hi = apr_hash_first(subPool.getPool(), mergeinfo);
-         hi;
-         hi = apr_hash_next(hi))
-    {
-        const void *path;
-        void *val;
-        apr_hash_this(hi, &path, NULL, &val);
-
-        jstring jpath =
-            JNIUtil::makeJString(reinterpret_cast<const char *>(path));
-        jobject jranges =
-            CreateJ::RevisionRangeList(reinterpret_cast<svn_rangelist_t *>(val));
-
-        env->CallVoidMethod(jmergeinfo, addRevisions, jpath, jranges);
-
-        env->DeleteLocalRef(jranges);
-        env->DeleteLocalRef(jpath);
-    }
-
-    env->DeleteLocalRef(clazz);
-
-    return jmergeinfo;
+    return CreateJ::Mergeinfo(mergeinfo, subPool.getPool());
 }
 
 void SVNClient::getMergeinfoLog(int type, const char *pathOrURL,
@@ -954,7 +905,7 @@ void SVNClient::propertySetRemote(const 
                                   const char *name,
                                   CommitMessage *message,
                                   JNIByteArray &value, bool force,
-                                  RevpropTable &revprops,
+                                  PropertyTable &revprops,
                                   CommitCallback *callback)
 {
     SVN::Pool subPool(pool);
@@ -1169,7 +1120,7 @@ void SVNClient::streamFileContent(const 
         return;
 
     SVN_JNI_ERR(svn_client_cat2(outputStream.getStream(subPool),
-                                path, pegRevision.revision(),
+                                intPath.c_str(), pegRevision.revision(),
                                 revision.revision(), ctx, subPool.getPool()),
                 );
 }
@@ -1465,19 +1416,14 @@ jobject SVNClient::revProperties(const c
                                         &set_rev, ctx, subPool.getPool()),
                 NULL);
 
-    return CreateJ::PropertyMap(props);
+    return CreateJ::PropertyMap(props, subPool.getPool());
 }
 
-struct info_baton
-{
-    std::vector<info_entry> infoVect;
-    apr_pool_t *pool;
-};
-
 void
-SVNClient::info2(const char *path, Revision &revision, Revision &pegRevision,
-                 svn_depth_t depth, StringArray &changelists,
-                 InfoCallback *callback)
+SVNClient::info2(const char *path,
+                 Revision &revision, Revision &pegRevision, svn_depth_t depth,
+                 svn_boolean_t fetchExcluded, svn_boolean_t fetchActualOnly,
+                 StringArray &changelists, InfoCallback *callback)
 {
     SVN_JNI_NULL_PTR_EX(path, "path", );
 
@@ -1492,7 +1438,7 @@ SVNClient::info2(const char *path, Revis
     SVN_JNI_ERR(svn_client_info3(checkedPath.c_str(),
                                  pegRevision.revision(),
                                  revision.revision(),
-                                 depth, FALSE, TRUE,
+                                 depth, fetchExcluded, fetchActualOnly,
                                  changelists.array(subPool),
                                  InfoCallback::callback, callback,
                                  ctx, subPool.getPool()), );
@@ -1525,6 +1471,63 @@ SVNClient::patch(const char *patchPath, 
                                  ctx, subPool.getPool()), );
 }
 
+jobject
+SVNClient::openRemoteSession(const char* path, int retryAttempts)
+{
+    static const svn_opt_revision_t HEAD = { svn_opt_revision_head, {0}};
+    static const svn_opt_revision_t NONE = { svn_opt_revision_unspecified, {0}};
+
+    SVN_JNI_NULL_PTR_EX(path, "path", NULL);
+
+    SVN::Pool subPool(pool);
+    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
+    if (ctx == NULL)
+        return NULL;
+
+    Path checkedPath(path, subPool);
+    SVN_JNI_ERR(checkedPath.error_occurred(), NULL);
+
+    struct PathInfo
+    {
+        std::string url;
+        std::string uuid;
+        static svn_error_t *callback(void *baton,
+                                     const char *,
+                                     const svn_client_info2_t *info,
+                                     apr_pool_t *)
+          {
+              PathInfo* const pi = static_cast<PathInfo*>(baton);
+              pi->url = info->URL;
+              pi->uuid = info->repos_UUID;
+              return SVN_NO_ERROR;
+          }
+    } path_info;
+
+    SVN_JNI_ERR(svn_client_info3(
+                    checkedPath.c_str(), &NONE,
+                    (svn_path_is_url(checkedPath.c_str()) ? &HEAD : &NONE),
+                    svn_depth_empty, FALSE, TRUE, NULL,
+                    PathInfo::callback, &path_info,
+                    ctx, subPool.getPool()),
+                NULL);
+
+    /* Decouple the RemoteSession's context from SVNClient's context
+       by creating a copy of the prompter here. */
+    Prompter* prompter = new Prompter(context.getPrompter());
+    if (!prompter)
+      return NULL;
+
+    jobject jremoteSession = RemoteSession::open(
+        retryAttempts, path_info.url.c_str(), path_info.uuid.c_str(),
+        context.getConfigDirectory(),
+        context.getUsername(), context.getPassword(),
+        prompter, context.getSelf(), context.getTunnelCallback());
+    if (JNIUtil::isJavaExceptionThrown())
+      delete prompter;
+
+    return jremoteSession;
+}
+
 ClientContext &
 SVNClient::getClientContext()
 {