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/08/09 18:34:42 UTC

svn commit: r1512383 - in /subversion/branches/javahl-1.7-extensions: ./ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/apache/subversion/ja...

Author: brane
Date: Fri Aug  9 16:34:41 2013
New Revision: 1512383

URL: http://svn.apache.org/r1512383
Log:
On the javahl-1.7-extensions branch: Sync JavaHL with trunk up to r1512372.

Added:
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp
      - copied unchanged from r1512372, subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_DiffLib.cpp
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
      - copied unchanged from r1512372, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteFileRevisionsCallback.java
      - copied unchanged from r1512372, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteFileRevisionsCallback.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteLocationSegmentsCallback.java
      - copied unchanged from r1512372, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteLocationSegmentsCallback.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/
      - copied from r1512372, subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
      - copied unchanged from r1512372, subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
Modified:
    subversion/branches/javahl-1.7-extensions/Makefile.in
    subversion/branches/javahl-1.7-extensions/build.conf
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/   (props changed)
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.cpp
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.h
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.cpp
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.h
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java
    subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java

Modified: subversion/branches/javahl-1.7-extensions/Makefile.in
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/Makefile.in?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/Makefile.in (original)
+++ subversion/branches/javahl-1.7-extensions/Makefile.in Fri Aug  9 16:34:41 2013
@@ -427,7 +427,7 @@ revision-install:
 install-static: @INSTALL_STATIC_RULES@
 
 # JavaHL target aliases
-javahl: mkdir-init javahl-java javahl-javah javahl-callback-javah javahl-types-javah javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
+javahl: mkdir-init javahl-java javahl-javah javahl-callback-javah javahl-remote-javah javahl-types-javah javahl-util-javah javahl-lib @JAVAHL_TESTS_TARGET@ javahl-compat
 install-javahl: javahl install-javahl-java install-javahl-javah install-javahl-lib
 javahl-compat: javahl-compat-java @JAVAHL_COMPAT_TESTS_TARGET@
 
@@ -618,9 +618,11 @@ doc-javahl:
 	  -sourcepath $(top_srcdir)/subversion/bindings/javahl/src \
 	  -link http://java.sun.com/javase/6/docs/api/ \
 	  org.tigris.subversion.javahl \
-      org.apache.subversion.javahl \
-      org.apache.subversion.javahl.callback \
-      org.apache.subversion.javahl.types
+	  org.apache.subversion.javahl \
+	  org.apache.subversion.javahl.callback \
+	  org.apache.subversion.javahl.remote \
+	  org.apache.subversion.javahl.types \
+	  org.apache.subversion.javahl.util
 
 doc-clean:
 	rm -rf $(top_srcdir)/doc/doxygen

Modified: subversion/branches/javahl-1.7-extensions/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/build.conf?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/build.conf (original)
+++ subversion/branches/javahl-1.7-extensions/build.conf Fri Aug  9 16:34:41 2013
@@ -61,6 +61,7 @@ private-built-includes =
         subversion/bindings/javahl/include/org_apache_subversion_javahl_remote_RemoteSession.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_remote_RemoteFactory.h
         subversion/bindings/javahl/include/org_apache_subversion_javahl_ConfigImpl_Category.h
+        subversion/bindings/javahl/include/org_apache_subversion_javahl_util_DiffLib.h
 
 test-scripts =
         subversion/tests/cmdline/*_tests.py
@@ -531,8 +532,9 @@ msvc-static = no
 type = java
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl
   subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
-  subversion/bindings/javahl/src/org/apache/subversion/javahl/types
   subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
+  subversion/bindings/javahl/src/org/apache/subversion/javahl/types
+  subversion/bindings/javahl/src/org/apache/subversion/javahl/util
 src-root = subversion/bindings/javahl/src
 sources = *.java
 install = javahl-java
@@ -576,19 +578,19 @@ package-roots = org
 #add-deps = javahl-compat-java
 add-deps = $(javahl_compat_java_DEPS)
 
-[javahl-types-javah]
-type = javah 
-path = subversion/bindings/javahl/src/org/apache/subversion/javahl/types
+[javahl-callback-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
-package = org.apache.subversion.javahl.types
+package = org.apache.subversion.javahl.callback
 sources = *.java
 add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
 [javahl-remote-javah]
-type = javah 
+type = javah
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl/remote
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
@@ -598,19 +600,30 @@ add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
-[javahl-callback-javah]
-type = javah 
-path = subversion/bindings/javahl/src/org/apache/subversion/javahl/callback
+[javahl-types-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/types
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include
-package = org.apache.subversion.javahl.callback
+package = org.apache.subversion.javahl.types
+sources = *.java
+add-deps = $(javahl_java_DEPS)
+install = javahl-javah
+link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
+
+[javahl-util-javah]
+type = javah
+path = subversion/bindings/javahl/src/org/apache/subversion/javahl/util
+classes = subversion/bindings/javahl/classes
+headers = subversion/bindings/javahl/include
+package = org.apache.subversion.javahl.util
 sources = *.java
 add-deps = $(javahl_java_DEPS)
 install = javahl-javah
 link-cmd = $(COMPILE_JAVAHL_JAVAH) -force
 
 [javahl-javah]
-type = javah 
+type = javah
 path = subversion/bindings/javahl/src/org/apache/subversion/javahl
 classes = subversion/bindings/javahl/classes
 headers = subversion/bindings/javahl/include

Propchange: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/bindings/javahl:r1509058-1512372

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.cpp?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.cpp (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.cpp Fri Aug  9 16:34:41 2013
@@ -1052,13 +1052,112 @@ CreateJ::StringSet(const apr_array_heade
   return CreateJ::Set(jstrs);
 }
 
-jobject CreateJ::PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool)
+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);
+
+  if (!map || (prop_hash == NULL && prop_diffs == NULL))
+    return;
+
   JNIEnv *env = JNIUtil::getEnv();
 
-  if (prop_hash == NULL)
+  // 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();
+    }
+
+  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;
+
+          const void* v_key;
+          void* v_val;
+
+          apr_hash_this(hi, &v_key, NULL, &v_val);
+          key = static_cast<const char*>(v_key);
+          val = static_cast<svn_string_t*>(v_val);
+
+          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();
+        }
+    }
+}
+
+jobject property_map(apr_hash_t *prop_hash, apr_array_header_t* prop_diffs,
+                     apr_pool_t* scratch_pool)
+{
+  SVN_ERR_ASSERT_NO_RETURN(!prop_hash != !prop_diffs
+                           || !prop_hash && !prop_diffs);
+
+  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())
@@ -1090,71 +1189,35 @@ jobject CreateJ::PropertyMap(apr_hash_t 
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
-  FillPropertyMap(map, prop_hash, scratch_pool, put_mid);
+  fill_property_map(map, prop_hash, prop_diffs, scratch_pool, put_mid);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
   return env->PopLocalFrame(map);
 }
+} // anonymous namespace
 
-void CreateJ::FillPropertyMap(jobject map, apr_hash_t* prop_hash,
-                              apr_pool_t* scratch_pool, jmethodID put_mid)
+jobject CreateJ::PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool)
 {
-  JNIEnv *env = JNIUtil::getEnv();
-
-  if (!map || !prop_hash)
-    return;
-
-  // 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();
-    }
-
-  if (!scratch_pool)
-    scratch_pool = apr_hash_pool_get(prop_hash);
-
-  apr_hash_index_t *hi;
-  int i = 0;
-  for (hi = apr_hash_first(scratch_pool, prop_hash);
-       hi; hi = apr_hash_next(hi), ++i)
-    {
-      const char *key;
-      svn_string_t *val;
-
-      const void *v_key;
-      void *v_val;
-
-      apr_hash_this(hi, &v_key, NULL, &v_val);
-      key = static_cast<const char*>(v_key);
-      val = static_cast<svn_string_t*>(v_val);
-
-      jstring jpropName = JNIUtil::makeJString(key);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NOTHING();
+  return property_map(prop_hash, NULL, scratch_pool);
+}
 
-      jbyteArray jpropVal = JNIUtil::makeJByteArray(
-                                    (const signed char *)val->data, val->len);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NOTHING();
+jobject CreateJ::PropertyMap(apr_array_header_t* prop_diffs,
+                             apr_pool_t* scratch_pool)
+{
+  return property_map(NULL, prop_diffs, scratch_pool);
+}
 
-      env->CallObjectMethod(map, put_mid, jpropName, jpropVal);
-      if (JNIUtil::isJavaExceptionThrown())
-        POP_AND_RETURN_NOTHING();
+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);
+}
 
-      env->DeleteLocalRef(jpropName);
-      env->DeleteLocalRef(jpropVal);
-    }
+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::Mergeinfo(svn_mergeinfo_t mergeinfo, apr_pool_t* scratch_pool)

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.h?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.h (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/CreateJ.h Fri Aug  9 16:34:41 2013
@@ -87,11 +87,19 @@ class CreateJ
   static jobject
   PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool = NULL);
 
+  static jobject
+  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
   Mergeinfo(svn_mergeinfo_t mergeinfo, apr_pool_t* scratch_pool);
 

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.cpp?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.cpp (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.cpp Fri Aug  9 16:34:41 2013
@@ -980,37 +980,29 @@ public:
     {
       LocationSegmentHandler* const self =
         static_cast<LocationSegmentHandler*>(baton);
-      SVN_ERR_ASSERT(self->m_jresult_list != NULL);
-      self->add(segment);
+      SVN_ERR_ASSERT(self->m_jcallback != NULL);
+      self->call(segment);
       SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
       return SVN_NO_ERROR;
     }
 
-  LocationSegmentHandler()
-    : m_jresult_list(NULL)
+  LocationSegmentHandler(jobject jcallback)
+    : m_jcallback(jcallback),
+      m_call_mid(0)
     {
       JNIEnv* env = JNIUtil::getEnv();
-      jclass cls = env->FindClass("java/util/ArrayList");
+      jclass cls = env->GetObjectClass(jcallback);
       if (JNIUtil::isJavaExceptionThrown())
         return;
 
-      static jmethodID mid = 0;
-      if (mid == 0)
-        {
-          mid = env->GetMethodID(cls, "<init>", "()V");
-          if (JNIUtil::isJavaExceptionThrown())
-            return;
-        }
-
-      jobject jresult_list = env->NewObject(cls, mid);
-      if (!JNIUtil::isJavaExceptionThrown() && jresult_list)
-        m_jresult_list = jresult_list;
+      m_call_mid = env->GetMethodID(
+          cls, "doSegment", "(L"JAVA_PACKAGE"/ISVNRemote$LocationSegment;)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
     }
 
-  jobject get() const { return m_jresult_list; }
-
 private:
-  void add(svn_location_segment_t* segment)
+  void call(svn_location_segment_t* segment)
     {
       JNIEnv* env = JNIUtil::getEnv();
       jclass cls = env->FindClass(JAVA_PACKAGE"/ISVNRemote$LocationSegment");
@@ -1026,60 +1018,157 @@ private:
             return;
         }
 
-      static jmethodID mid_add = 0;
-      if (mid_add == 0)
-        {
-          jclass list_cls = env->FindClass("java/util/ArrayList");
-          if (JNIUtil::isJavaExceptionThrown())
-            return;
-          mid_add = env->GetMethodID(list_cls, "add",
-                                     "(Ljava/lang/Object;)Z");
-          if (JNIUtil::isJavaExceptionThrown())
-            return;
-        }
-
       jstring jpath = JNIUtil::makeJString(segment->path);
       if (JNIUtil::isJavaExceptionThrown())
         return;
 
-      env->CallBooleanMethod(m_jresult_list, mid_add,
-                             env->NewObject(cls, mid, jpath,
-                                            jlong(segment->range_start),
-                                            jlong(segment->range_end)));
+      env->CallVoidMethod(m_jcallback, m_call_mid,
+                          env->NewObject(cls, mid, jpath,
+                                         jlong(segment->range_start),
+                                         jlong(segment->range_end)));
       if (JNIUtil::isJavaExceptionThrown())
         return;
       env->DeleteLocalRef(jpath);
     }
 
-  jobject m_jresult_list;
+  jobject m_jcallback;
+  jmethodID m_call_mid;
 };
 } // anonymous namespace
 
-jobject
+void
 RemoteSession::getLocationSegments(jstring jpath, jlong jpeg_revision,
-                                   jlong jstart_revision, jlong jend_revision)
+                                   jlong jstart_revision, jlong jend_revision,
+                                   jobject jcallback)
 {
   SVN::Pool subPool(pool);
   Relpath path(jpath, subPool);
   if (JNIUtil::isExceptionThrown())
-    return NULL;
-  SVN_JNI_ERR(path.error_occurred(), NULL);
+    return;
+  SVN_JNI_ERR(path.error_occurred(), );
 
-  LocationSegmentHandler handler;
+  LocationSegmentHandler handler(jcallback);
   if (JNIUtil::isExceptionThrown())
-    return NULL;
+    return ;
 
   SVN_JNI_ERR(svn_ra_get_location_segments(m_session, path.c_str(),
                                            svn_revnum_t(jpeg_revision),
                                            svn_revnum_t(jstart_revision),
                                            svn_revnum_t(jend_revision),
                                            handler.callback, &handler,
-                                           subPool.getPool()),
-              NULL);
-  return handler.get();
+                                           subPool.getPool()),);
+}
+
+namespace {
+class FileRevisionHandler
+{
+public:
+  static svn_error_t* callback(void* baton,
+                               const char* path, svn_revnum_t revision,
+                               apr_hash_t* revision_props,
+                               // We ignore the deltas as they're not
+                               // exposed in the JavaHL API.
+                               svn_boolean_t result_of_merge,
+                               svn_txdelta_window_handler_t*, void**,
+                               apr_array_header_t* prop_diffs,
+                               apr_pool_t* scratch_pool)
+    {
+      FileRevisionHandler* const self =
+        static_cast<FileRevisionHandler*>(baton);
+      SVN_ERR_ASSERT(self->m_jcallback != NULL);
+      self->call(path, revision, revision_props,
+                result_of_merge, prop_diffs, scratch_pool);
+      SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
+      return SVN_NO_ERROR;
+    }
+
+  FileRevisionHandler(jobject jcallback)
+    : m_jcallback(jcallback),
+      m_call_mid(0)
+    {
+      JNIEnv* env = JNIUtil::getEnv();
+      jclass cls = env->GetObjectClass(jcallback);
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+
+      m_call_mid = env->GetMethodID(
+          cls, "doRevision", "(L"JAVA_PACKAGE"/ISVNRemote$FileRevision;)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+    }
+
+private:
+  void call(const char* path, svn_revnum_t revision,
+           apr_hash_t* revision_props,
+           svn_boolean_t result_of_merge,
+           apr_array_header_t* prop_diffs,
+           apr_pool_t* scratch_pool)
+    {
+      JNIEnv* env = JNIUtil::getEnv();
+      jclass cls = env->FindClass(JAVA_PACKAGE"/ISVNRemote$FileRevision");
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+
+      static jmethodID mid = 0;
+      if (mid == 0)
+        {
+          mid = env->GetMethodID(cls, "<init>",
+                                 "(Ljava/lang/String;JZ"
+                                 "Ljava/util/Map;Ljava/util/Map;)V");
+          if (JNIUtil::isJavaExceptionThrown())
+            return;
+        }
+
+      jstring jpath = JNIUtil::makeJString(path);
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+      jobject jrevprops = CreateJ::PropertyMap(revision_props, scratch_pool);
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+      jobject jpropdelta = CreateJ::PropertyMap(prop_diffs, scratch_pool);
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+
+      env->CallVoidMethod(m_jcallback, m_call_mid,
+                          env->NewObject(cls, mid, jpath, jlong(revision),
+                                         jboolean(result_of_merge),
+                                         jrevprops, jpropdelta));
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+      env->DeleteLocalRef(jpath);
+      env->DeleteLocalRef(jrevprops);
+      env->DeleteLocalRef(jpropdelta);
+    }
+
+  jobject m_jcallback;
+  jmethodID m_call_mid;
+};
+} // anonymous namespace
+
+void
+RemoteSession::getFileRevisions(jstring jpath,
+                                jlong jstart_revision, jlong jend_revision,
+                                jboolean jinclude_merged_revisions,
+                                jobject jcallback)
+{
+  SVN::Pool subPool(pool);
+  Relpath path(jpath, subPool);
+  if (JNIUtil::isExceptionThrown())
+    return;
+  SVN_JNI_ERR(path.error_occurred(), );
+
+  FileRevisionHandler handler(jcallback);
+  if (JNIUtil::isExceptionThrown())
+    return;
+
+  SVN_JNI_ERR(svn_ra_get_file_revs2(m_session, path.c_str(),
+                                    svn_revnum_t(jstart_revision),
+                                    svn_revnum_t(jend_revision),
+                                    bool(jinclude_merged_revisions),
+                                    handler.callback, &handler,
+                                    subPool.getPool()),);
 }
 
-// TODO: getFileRevisions
 // TODO: lock
 // TODO: unlock
 // TODO: getLock

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.h?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.h (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/RemoteSession.h Fri Aug  9 16:34:41 2013
@@ -95,8 +95,13 @@ class RemoteSession : public SVNBase
     jobject stat(jstring jpath, jlong jrevision);
     jobject getLocations(jstring jpath, jlong jpeg_revision,
                          jobject jlocation_revisions);
-    jobject getLocationSegments(jstring jpath, jlong jpeg_revision,
-                                jlong jstart_revision, jlong jend_revision);
+    void getLocationSegments(jstring jpath, jlong jpeg_revision,
+                             jlong jstart_revision, jlong jend_revision,
+                             jobject jcallback);
+    void getFileRevisions(jstring jpath,
+                          jlong jstart_revision, jlong jend_revision,
+                          jboolean jinclude_merged_revisions,
+                          jobject jcallback);
     // TODO: getFileRevisions
     // TODO: lock
     // TODO: unlock

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp Fri Aug  9 16:34:41 2013
@@ -295,20 +295,38 @@ Java_org_apache_subversion_javahl_remote
   return ras->getLocations(jpath, jpeg_revision, jlocation_revisions);
 }
 
-JNIEXPORT jobject JNICALL
+JNIEXPORT void JNICALL
 Java_org_apache_subversion_javahl_remote_RemoteSession_getLocationSegments(
     JNIEnv *env, jobject jthis, jstring jpath, jlong jpeg_revision,
-    jlong jstart_revision, jlong jend_revision)
+    jlong jstart_revision, jlong jend_revision, jobject jcallback)
 {
   JNIEntry(SVNReposAccess, getLocationSegments);
   RemoteSession *ras = RemoteSession::getCppObject(jthis);
-  CPPADDR_NULL_PTR(ras, NULL);
+  CPPADDR_NULL_PTR(ras, );
+
+  if (jcallback == NULL)
+    JNIUtil::throwNullPointerException("handler");
+  ras->getLocationSegments(jpath, jpeg_revision,
+                           jstart_revision, jend_revision,
+                           jcallback);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_getFileRevisions(
+    JNIEnv *env, jobject jthis, jstring jpath,
+    jlong jstart_revision, jlong jend_revision,
+    jboolean jinclude_merged_revisions, jobject jcallback)
+{
+  JNIEntry(SVNReposAccess, getFileRevisions);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras, );
 
-  return ras->getLocationSegments(jpath, jpeg_revision,
-                                  jstart_revision, jend_revision);
+  if (jcallback == NULL)
+    JNIUtil::throwNullPointerException("handler");
+  ras->getFileRevisions(jpath, jstart_revision, jend_revision,
+                        jinclude_merged_revisions, jcallback);
 }
 
-// TODO: getFileRevisions
 // TODO: lock
 // TODO: unlock
 // TODO: getLock

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java Fri Aug  9 16:34:41 2013
@@ -470,7 +470,7 @@ public interface ISVNRemote
             throws ClientException;
 
     /**
-     * The object returned from {@link getLocationSegments}.
+     * The object returned from {@link #getLocationSegments}.
      */
     public static class LocationSegment implements java.io.Serializable
     {
@@ -512,7 +512,31 @@ public interface ISVNRemote
     }
 
     /**
-     * Return a lost of segments in the location history of <code>path</code>
+     * Call <code>handler</code> for every segment in the location
+     * history of <code>path</code> at <code>pegRevision</code>,
+     * working backwards in time from <code>startRevision</code> to
+     * <code>endRevision</code>.
+     *
+     * @param path A session-relative path.
+     * @param pegRevision The peg revision to find <code>path</code> in.
+     * @param startRevision The upper bound of the revision range. Use
+     * {@link org.apache.subversion.javahl.types.Revision#SVN_INVALID_REVNUM}
+     *        to indicate HEAD.
+     * @param endRevision The lower bound of the revision range. Use
+     * {@link org.apache.subversion.javahl.types.Revision#SVN_INVALID_REVNUM}
+     *        to trace the history of the object to its origin.
+     * @param handler The callback handler.
+     * @throws ClientException
+     */
+    void getLocationSegments(String path,
+                             long pegRevision,
+                             long startRevision,
+                             long endRevision,
+                             RemoteLocationSegmentsCallback handler)
+            throws ClientException;
+
+    /**
+     * Return a list of segments in the location history of <code>path</code>
      * at <code>pegRevision</code>, working backwards in time from
      * <code>startRevision</code> to <code>endRevision</code>.
      *
@@ -532,18 +556,154 @@ public interface ISVNRemote
                                               long endRevision)
             throws ClientException;
 
-    // TODO: getFileRevisions
+    /**
+     * The object returned by {@link #getFileRevisions}.
+     */
+    public final class FileRevision  implements java.io.Serializable
+    {
+        // Update the serialVersionUID when there is a incompatible change
+        // made to this class.
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Private constructor called by the native implementation.
+         */
+        private FileRevision(String path, long revision,
+                             boolean resultOfMerge,
+                             Map<String, byte[]> revisionProperties,
+                             Map<String, byte[]> propertiesDelta)
+        {
+            this.path = path;
+            this.revision = revision;
+            this.resultOfMerge = resultOfMerge;
+            this.revisionProperties = revisionProperties;
+            this.propertiesDelta = propertiesDelta;
+        }
+
+        /**
+         * @return The path of the file in this revision.
+         */
+        public String getPath() { return path; }
+
+        /**
+         * @return The revision associated with the path.
+         */
+        public long getRevision() { return revision; }
+
+        /**
+         * @return A flag indicating that this revision was the result
+         * of a merge.
+         */
+        public boolean isResultOfMerge() { return resultOfMerge; }
+
+        /**
+         * @return The list of revision properties.
+         */
+        public Map<String, byte[]> getRevisionProperties()
+        {
+            return revisionProperties;
+        }
+
+        /**
+         * @return The changes that were made to the file's properties
+         * in this revision. This map will contain only added,
+         * modified and deleted properties. Deleted properties will
+         * have <code>null</code> values.
+         */
+        public Map<String, byte[]> getPropertiesDelta()
+        {
+            return propertiesDelta;
+        }
+
+        private String path;
+        private long revision;
+        private boolean resultOfMerge;
+        private Map<String, byte[]> revisionProperties;
+        private Map<String, byte[]> propertiesDelta;
+    }
+
+    /**
+     * Call <code>handler</code> for each of a subset of the
+     * interesting revisions of a file <code>path</code> as seen in
+     * revision <code>endRevision</code>.
+     * <p>
+     * If there is an interesting revision of the file that is less
+     * than or equal to <code>startRevision</code>, the iteration will
+     * begin at that revision.  Otherwise the iteration will begin at
+     * the first revision of the file in the repository, which has to
+     * be less than or equal to <code>endRevision</code>.  Note that
+     * if the function succeeds, <code>handler</code> will be called
+     * at least once.
+     * <p>
+     * <b>Note:</b> This functionality is not available in pre-1.1
+     * servers.  If the server doesn't implement it, an alternative
+     * (but much slower) implementation based on {@link #getLog} is
+     * used.
+     * <p>
+     * <b>Note:</b> With Subversion 1.8 and newer servers this
+     * function supports reversion of the revision range for when
+     * <code>includeMergedRevisions</code> is <code>false</code>.
+     *
+     * @param path A path relative to the session URL.
+     * @param startRevision The lower bound of the revision interval.
+     * @param endRevision the upper bound of the revision interval.
+     * @param includeMergedRevisions When <code>true</code>, revisions that
+     *    contributed to a merge are included in the result.
+     * @throws ClientException
+     */
+    void getFileRevisions(String path,
+                          long startRevision, long endRevision,
+                          boolean includeMergedRevisions,
+                          RemoteFileRevisionsCallback handler)
+            throws ClientException;
+
+    /**
+     * Retrieve a subset of the interesting revisions of a file
+     * <code>path</code> as seen in revision <code>endRevision</code>.
+     * <p>
+     * If there is an interesting revision of the file that is less
+     * than or equal to <code>startRevision</code>, the iteration will
+     * begin at that revision.  Otherwise the iteration will begin at
+     * the first revision of the file in the repository, which has to
+     * be less than or equal to <code>endRevision</code>.  Note that
+     * if the function succeeds, the returned list will contain at
+     * least one element.
+     * <p>
+     * <b>Note:</b> This functionality is not available in pre-1.1
+     * servers.  If the server doesn't implement it, an alternative
+     * (but much slower) implementation based on {@link #getLog} is
+     * used.
+     * <p>
+     * <b>Note:</b> With Subversion 1.8 and newer servers this
+     * function supports reversion of the revision range for when
+     * <code>includeMergedRevisions</code> is <code>false</code>.
+     *
+     * @param path A path relative to the session URL.
+     * @param startRevision The lower bound of the revision interval.
+     * @param endRevision the upper bound of the revision interval.
+     * @param includeMergedRevisions When <code>true</code>, revisions that
+     *    contributed to a merge are included in the result.
+     * @throws ClientException
+     */
+    List<FileRevision> getFileRevisions(String path,
+                                        long startRevision, long endRevision,
+                                        boolean includeMergedRevisions)
+            throws ClientException;
+
+
     // TODO: lock
     // TODO: unlock
     // TODO: getLock
 
     /**
      * Return a dictionary containing all locks on or below the given path.
+     * <p>
+     * <b>Note:</b> It is not considered an error if <code>path</code> does
+     * not exist in HEAD. Such a search will simply return no locks.
+     * <p>
+     * <b>Note:</b>This functionality is not available in pre-1.2 servers.
      * @param path A path relative to the sessionn URL
      * @param depth The recursion depth
-     * @note It is not considered an error for the path to not exist in HEAD.
-     *       Such a search will simply return no locks.
-     * @note This functionality is not available in pre-1.2 servers.
      * @throws ClientException
      */
     Map<String, Lock> getLocks(String path, Depth depth)

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java Fri Aug  9 16:34:41 2013
@@ -34,6 +34,7 @@ import org.apache.subversion.javahl.Oper
 import org.apache.subversion.javahl.ClientException;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -207,13 +208,68 @@ public class RemoteSession extends JNIOb
             throws ClientException;
 
     public native
-        List<LocationSegment> getLocationSegments(String path,
-                                                  long pegRevision,
-                                                  long startRevision,
-                                                  long endRevision)
+        void getLocationSegments(String path,
+                                 long pegRevision,
+                                 long startRevision,
+                                 long endRevision,
+                                 RemoteLocationSegmentsCallback handler)
             throws ClientException;
 
-    // TODO: getFileRevisions
+    private static class GetLocationSegmentsHandler
+        implements RemoteLocationSegmentsCallback
+    {
+        public List<LocationSegment> locationSegments = null;
+        public void doSegment(LocationSegment locationSegment)
+        {
+            if (locationSegments == null)
+                locationSegments = new ArrayList<LocationSegment>();
+            locationSegments.add(locationSegment);
+        }
+    }
+
+    public List<LocationSegment> getLocationSegments(String path,
+                                                     long pegRevision,
+                                                     long startRevision,
+                                                     long endRevision)
+            throws ClientException
+    {
+        final GetLocationSegmentsHandler handler = new GetLocationSegmentsHandler();
+        getLocationSegments(path, pegRevision, startRevision, endRevision, handler);
+        return handler.locationSegments;
+    }
+
+    public native
+        void getFileRevisions(String path,
+                              long startRevision,
+                              long endRevision,
+                              boolean includeMergedRevisions,
+                              RemoteFileRevisionsCallback handler)
+            throws ClientException;
+
+    private static class GetFileRevisionsHandler
+        implements RemoteFileRevisionsCallback
+    {
+        public List<FileRevision> fileRevisions = null;
+        public void doRevision(FileRevision fileRevision)
+        {
+            if (fileRevisions == null)
+                fileRevisions = new ArrayList<FileRevision>();
+            fileRevisions.add(fileRevision);
+        }
+    }
+
+    public List<FileRevision> getFileRevisions(String path,
+                                               long startRevision,
+                                               long endRevision,
+                                               boolean includeMergedRevisions)
+            throws ClientException
+    {
+        final GetFileRevisionsHandler handler = new GetFileRevisionsHandler();
+        getFileRevisions(path, startRevision, endRevision,
+                         includeMergedRevisions, handler);
+        return handler.fileRevisions;
+    }
+
     // TODO: lock
     // TODO: unlock
     // TODO: getLock

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/RunTests.java Fri Aug  9 16:34:41 2013
@@ -91,9 +91,10 @@ public class RunTests
             if (testCases == null || testCases.length == 0)
             {
                 // Add default test suites.
-                suite.addTestSuite(SVNReposTests.class);
-                suite.addTestSuite(SVNRemoteTests.class);
                 suite.addTestSuite(BasicTests.class);
+                suite.addTestSuite(UtilTests.class);
+                suite.addTestSuite(SVNRemoteTests.class);
+                suite.addTestSuite(SVNReposTests.class);
             }
             else
             {

Modified: subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1512383&r1=1512382&r2=1512383&view=diff
==============================================================================
--- subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java (original)
+++ subversion/branches/javahl-1.7-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java Fri Aug  9 16:34:41 2013
@@ -624,4 +624,16 @@ public class SVNRemoteTests extends SVNT
         assertEquals(1, seg.getStartRevision());
         assertEquals(1, seg.getEndRevision());
     }
+
+    public void testGetFileRevisions() throws Exception
+    {
+        ISVNRemote session = getSession();
+
+        List<ISVNRemote.FileRevision> result =
+            session.getFileRevisions("iota", 0, 1, true);
+        assertEquals(1, result.size());
+        ISVNRemote.FileRevision rev = result.get(0);
+        assertEquals("/iota", rev.getPath());
+        assertFalse(rev.isResultOfMerge());
+    }
 }