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/07/05 16:42:41 UTC

svn commit: r1500026 - in /subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl: ./ native/ src/org/apache/subversion/javahl/ src/org/apache/subversion/javahl/callback/ src/org/apache/subversion/javahl/remote/ src/org/apache/subversion/...

Author: brane
Date: Fri Jul  5 14:42:40 2013
New Revision: 1500026

URL: http://svn.apache.org/r1500026
Log:
On the javahl-1.8-extensions branch: Sync JavaHL with trunk up to r1500023.

Modified:
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/   (props changed)
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/BlameCallback.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.h
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EditorProxy.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.h
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LogMessageCallback.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/ProplistCallback.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.h
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RevisionRange.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/SVNClient.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteStatus.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/Mergeinfo.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/RevisionRange.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
    subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java

Propchange: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/bindings/javahl:r1499153-1500023

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/BlameCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/BlameCallback.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/BlameCallback.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/BlameCallback.cpp Fri Jul  5 14:42:40 2013
@@ -104,14 +104,14 @@ BlameCallback::singleLine(svn_revnum_t s
     }
 
   // convert the parameters to their Java relatives
-  jobject jrevProps = CreateJ::PropertyMap(revProps);
+  jobject jrevProps = CreateJ::PropertyMap(revProps, pool);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN(SVN_NO_ERROR);
 
   jobject jmergedRevProps = NULL;
   if (mergedRevProps != NULL)
     {
-      jmergedRevProps = CreateJ::PropertyMap(mergedRevProps);
+      jmergedRevProps = CreateJ::PropertyMap(mergedRevProps, pool);
       if (JNIUtil::isJavaExceptionThrown())
         POP_AND_RETURN(SVN_NO_ERROR);
     }

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.cpp Fri Jul  5 14:42:40 2013
@@ -36,6 +36,7 @@
 
 #include "svn_path.h"
 #include "svn_props.h"
+#include "svn_mergeinfo.h"
 #include "private/svn_wc_private.h"
 
 jobject
@@ -1141,7 +1142,7 @@ CreateJ::StringSet(const apr_array_heade
   return CreateJ::Set(jstrs);
 }
 
-jobject CreateJ::PropertyMap(apr_hash_t *prop_hash)
+jobject CreateJ::PropertyMap(apr_hash_t *prop_hash, apr_pool_t* scratch_pool)
 {
   JNIEnv *env = JNIUtil::getEnv();
 
@@ -1179,7 +1180,7 @@ jobject CreateJ::PropertyMap(apr_hash_t 
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
-  FillPropertyMap(map, prop_hash, put_mid);
+  FillPropertyMap(map, prop_hash, scratch_pool, put_mid);
   if (JNIUtil::isJavaExceptionThrown())
     POP_AND_RETURN_NULL;
 
@@ -1187,7 +1188,7 @@ jobject CreateJ::PropertyMap(apr_hash_t 
 }
 
 void CreateJ::FillPropertyMap(jobject map, apr_hash_t* prop_hash,
-                              jmethodID put_mid)
+                              apr_pool_t* scratch_pool, jmethodID put_mid)
 {
   JNIEnv *env = JNIUtil::getEnv();
 
@@ -1210,8 +1211,11 @@ void CreateJ::FillPropertyMap(jobject ma
         POP_AND_RETURN_NOTHING();
     }
 
+  if (!scratch_pool)
+    scratch_pool = apr_hash_pool_get(prop_hash);
+
   apr_hash_index_t *hi;
-  for (hi = apr_hash_first(apr_hash_pool_get(prop_hash), prop_hash);
+  for (hi = apr_hash_first(scratch_pool, prop_hash);
        hi; hi = apr_hash_next(hi))
     {
       const char *key;
@@ -1321,6 +1325,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));
+
+      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/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.h?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CreateJ.h Fri Jul  5 14:42:40 2013
@@ -31,6 +31,7 @@
 #include "svn_wc.h"
 #include "svn_repos.h"
 #include "svn_client.h"
+#include "svn_mergeinfo.h"
 
 #include <vector>
 
@@ -87,15 +88,19 @@ class CreateJ
   StringSet(const apr_array_header_t *strings);
 
   static jobject
-  PropertyMap(apr_hash_t *prop_hash);
+  PropertyMap(apr_hash_t *prop_hash, 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 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/javahl-1.8-extensions/subversion/bindings/javahl/native/EditorProxy.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EditorProxy.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EditorProxy.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EditorProxy.cpp Fri Jul  5 14:42:40 2013
@@ -151,7 +151,7 @@ EditorProxy::cb_add_directory(void *bato
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jobject jchildren = (!children ? NULL : CreateJ::StringSet(children));
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(
@@ -190,7 +190,7 @@ EditorProxy::cb_add_file(void *baton,
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jobject jcontents = NULL;     // FIXME: input stream proxy
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(
@@ -225,7 +225,7 @@ EditorProxy::cb_add_symlink(void *baton,
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jstring jtarget = JNIUtil::makeJString(target);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(
@@ -293,7 +293,7 @@ EditorProxy::cb_alter_directory(void *ba
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jobject jchildren = (!children ? NULL : CreateJ::StringSet(children));
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(
@@ -333,7 +333,7 @@ EditorProxy::cb_alter_file(void *baton,
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jobject jcontents = NULL;     // FIXME: input stream proxy
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(
@@ -369,7 +369,7 @@ EditorProxy::cb_alter_symlink(void *bato
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
   jstring jtarget = JNIUtil::makeJString(target);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
-  jobject jprops = CreateJ::PropertyMap(props);
+  jobject jprops = CreateJ::PropertyMap(props, scratch_pool);
   SVN_JNI_CATCH(,SVN_ERR_RA_SVN_EDIT_ABORTED);
 
   SVN_JNI_CATCH(

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.cpp Fri Jul  5 14:42:40 2013
@@ -219,6 +219,14 @@ svn_depth_t EnumMapper::toDepth(jobject 
   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/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.h?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/EnumMapper.h Fri Jul  5 14:42:40 2013
@@ -51,6 +51,8 @@ class EnumMapper
   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/javahl-1.8-extensions/subversion/bindings/javahl/native/LogMessageCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LogMessageCallback.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LogMessageCallback.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LogMessageCallback.cpp Fri Jul  5 14:42:40 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/javahl-1.8-extensions/subversion/bindings/javahl/native/ProplistCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/ProplistCallback.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/ProplistCallback.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/ProplistCallback.cpp Fri Jul  5 14:42:40 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/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.cpp Fri Jul  5 14:42:40 2013
@@ -465,7 +465,7 @@ RemoteSession::getRevisionProperties(jlo
                                   &props, subPool.getPool()),
               NULL);
 
-  return CreateJ::PropertyMap(props);
+  return CreateJ::PropertyMap(props, subPool.getPool());
 }
 
 jbyteArray
@@ -511,7 +511,7 @@ RemoteSession::getFile(jlong jrevision, 
 
   if (jproperties)
     {
-      CreateJ::FillPropertyMap(jproperties, props);
+      CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
       if (JNIUtil::isExceptionThrown())
         return SVN_INVALID_REVNUM;
     }
@@ -524,6 +524,9 @@ void fill_dirents(const char* base_url, 
                   jobject jdirents, apr_hash_t* dirents,
                   apr_pool_t* scratch_pool)
 {
+  if (!dirents)
+    return;
+
   base_url = apr_pstrcat(scratch_pool, base_url, "/", base_relpath, NULL);
   base_url = svn_uri_canonicalize(base_url, scratch_pool);
   svn_stringbuf_t* abs_path = svn_stringbuf_create(base_url, scratch_pool);
@@ -630,7 +633,7 @@ RemoteSession::getDirectory(jlong jrevis
 
   if (jproperties)
     {
-      CreateJ::FillPropertyMap(jproperties, props);
+      CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
       if (JNIUtil::isExceptionThrown())
         return SVN_INVALID_REVNUM;
     }
@@ -638,7 +641,118 @@ RemoteSession::getDirectory(jlong jrevis
   return fetched_rev;
 }
 
-// TODO: getMergeinfo
+namespace {
+const apr_array_header_t*
+build_string_array(const Iterator& iter,
+                   bool contains_relpaths, SVN::Pool& pool)
+{
+  apr_pool_t* result_pool = pool.getPool();
+  apr_array_header_t* array = apr_array_make(
+      result_pool, 0, sizeof(const char*));
+  while (iter.hasNext())
+    {
+      const char* element;
+      jstring jitem = (jstring)iter.next();
+      if (contains_relpaths)
+        {
+          Relpath item(jitem, pool);
+          if (JNIUtil::isExceptionThrown())
+            return NULL;
+          SVN_JNI_ERR(item.error_occurred(), NULL);
+          element = apr_pstrdup(result_pool, item.c_str());
+        }
+      else
+        {
+          JNIStringHolder item(jitem);
+          if (JNIUtil::isJavaExceptionThrown())
+            return NULL;
+          element = item.pstrdup(result_pool);
+        }
+      APR_ARRAY_PUSH(array, const char*) = element;
+    }
+  return array;
+}
+}
+
+jobject
+RemoteSession::getMergeinfo(jobject jpaths, jlong jrevision, jobject jinherit,
+                            jboolean jinclude_descendants)
+{
+  Iterator paths_iter(jpaths);
+  if (JNIUtil::isExceptionThrown())
+    return NULL;
+
+  SVN::Pool subPool(pool);
+  const apr_array_header_t* paths =
+    build_string_array(paths_iter, true, subPool);
+  if (JNIUtil::isJavaExceptionThrown())
+    return NULL;
+
+  svn_mergeinfo_catalog_t catalog;
+  SVN_JNI_ERR(svn_ra_get_mergeinfo(
+                  m_session, &catalog, paths, svn_revnum_t(jrevision),
+                  EnumMapper::toMergeinfoInheritance(jinherit),
+                  bool(jinclude_descendants),
+                  subPool.getPool()),
+              NULL);
+  if (catalog == NULL)
+    return NULL;
+
+  JNIEnv* env = JNIUtil::getEnv();
+  jclass cls = env->FindClass("java/util/HashMap");
+  if (JNIUtil::isExceptionThrown())
+    return NULL;
+
+  static jmethodID ctor_mid = 0;
+  if (0 == ctor_mid)
+    {
+      ctor_mid = env->GetMethodID(cls, "<init>", "()V");
+      if (JNIUtil::isExceptionThrown())
+        return NULL;
+    }
+
+  static jmethodID put_mid = 0;
+  if (0 == put_mid)
+    {
+      put_mid = env->GetMethodID(cls, "put",
+                                 "(Ljava/lang/Object;"
+                                 "Ljava/lang/Object;)"
+                                 "Ljava/lang/Object;");
+      if (JNIUtil::isExceptionThrown())
+        return NULL;
+    }
+
+  jobject jcatalog = env->NewObject(cls, ctor_mid);
+  if (JNIUtil::isExceptionThrown())
+    return NULL;
+
+  for (apr_hash_index_t* hi = apr_hash_first(subPool.getPool(), catalog);
+       hi; hi = apr_hash_next(hi))
+    {
+      const void *v_key;
+      void *v_val;
+      apr_hash_this(hi, &v_key, NULL, &v_val);
+      const char* key = static_cast<const char*>(v_key);
+      svn_mergeinfo_t val = static_cast<svn_mergeinfo_t>(v_val);
+
+      jstring jpath = JNIUtil::makeJString(key);
+      if (JNIUtil::isExceptionThrown())
+        return NULL;
+      jobject jmergeinfo = CreateJ::Mergeinfo(val, subPool.getPool());
+      if (JNIUtil::isExceptionThrown())
+        return NULL;
+
+      env->CallObjectMethod(jcatalog, put_mid, jpath, jmergeinfo);
+      if (JNIUtil::isExceptionThrown())
+        return NULL;
+
+      env->DeleteLocalRef(jpath);
+      env->DeleteLocalRef(jmergeinfo);
+    }
+
+  return jcatalog;
+}
+
 // TODO: update
 // TODO: switch
 
@@ -657,7 +771,7 @@ status_fetch_props_func(apr_hash_t **pro
 {
   //DEBUG:fprintf(stderr, "  (n) status_fetch_props_func('%s', r%lld)\n",
   //DEBUG:        path, static_cast<long long>(base_revision));
-  *props = apr_hash_make(scratch_pool);
+  *props = apr_hash_make(result_pool);
   return SVN_NO_ERROR;
 }
 
@@ -752,39 +866,6 @@ RemoteSession::status(jobject jthis, jst
 
 // TODO: diff
 
-namespace {
-const apr_array_header_t*
-build_string_array(const Iterator& iter,
-                   bool contains_relpaths, SVN::Pool& pool)
-{
-  apr_pool_t* result_pool = pool.getPool();
-  apr_array_header_t* array = apr_array_make(
-      result_pool, 0, sizeof(const char*));
-  while (iter.hasNext())
-    {
-      const char* element;
-      jstring jitem = (jstring)iter.next();
-      if (contains_relpaths)
-        {
-          Relpath item(jitem, pool);
-          if (JNIUtil::isExceptionThrown())
-            return NULL;
-          SVN_JNI_ERR(item.error_occurred(), NULL);
-          element = apr_pstrdup(result_pool, item.c_str());
-        }
-      else
-        {
-          JNIStringHolder item(jitem);
-          if (JNIUtil::isJavaExceptionThrown())
-            return NULL;
-          element = item.pstrdup(result_pool);
-        }
-      APR_ARRAY_PUSH(array, const char*) = element;
-    }
-  return array;
-}
-}
-
 void
 RemoteSession::getLog(jobject jpaths,
                       jlong jstartrev, jlong jendrev, jint jlimit,

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.h?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RemoteSession.h Fri Jul  5 14:42:40 2013
@@ -79,7 +79,8 @@ class RemoteSession : public SVNBase
                   jobject jcontents, jobject jproperties);
     jlong getDirectory(jlong jrevision, jstring jpath, jint jdirent_fields,
                        jobject jdirents, jobject jproperties);
-    // TODO: getMergeinfo
+    jobject getMergeinfo(jobject jpaths, jlong jrevision, jobject jinherit,
+                         jboolean jinclude_descendants);
     // TODO: update
     // TODO: switch
     void status(jobject jthis, jstring jstatus_target,

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RevisionRange.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RevisionRange.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RevisionRange.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/RevisionRange.cpp Fri Jul  5 14:42:40 2013
@@ -112,13 +112,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/javahl-1.8-extensions/subversion/bindings/javahl/native/SVNClient.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/SVNClient.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/SVNClient.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/SVNClient.cpp Fri Jul  5 14:42:40 2013
@@ -752,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;
@@ -768,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,
@@ -1468,7 +1416,7 @@ jobject SVNClient::revProperties(const c
                                         &set_rev, ctx, subPool.getPool()),
                 NULL);
 
-    return CreateJ::PropertyMap(props);
+    return CreateJ::PropertyMap(props, subPool.getPool());
 }
 
 struct info_baton

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp Fri Jul  5 14:42:40 2013
@@ -213,7 +213,18 @@ Java_org_apache_subversion_javahl_remote
                            jdirent_fields, jdirents, jproperties);
 }
 
-// TODO: getMergeinfo
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_getMergeinfo(
+    JNIEnv *env, jobject jthis, jobject jpaths, jlong jrevision,
+    jobject jinherit, jboolean jinclude_descendants)
+{
+  JNIEntry(SVNReposAccess, getMergeinfo);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras, NULL);
+
+  return ras->getMergeinfo(jpaths, jrevision, jinherit, jinclude_descendants);
+}
+
 // TODO: update
 // TODO: switch
 

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java Fri Jul  5 14:42:40 2013
@@ -269,8 +269,6 @@ public interface ISVNRemote
      * <code>properties</code> may not perform any ISVNRemote
      * operations using this session.
      * @return The revision of the directory that was retreived.
-     * @throws IllegalArgumentException if <code>direntFields</code>
-     *         is less than or equal to 0.
      * @throws ClientException
      */
     long getDirectory(long revision, String path,
@@ -279,7 +277,42 @@ public interface ISVNRemote
                       Map<String, byte[]> properties)
             throws ClientException;
 
-    // TODO: getMergeinfo
+    /**
+     * Retreive the merginfo for <code>paths</code>, whose elements
+     * are relative to the session's URL. The request will fail if any
+     * one of <code>paths</code> does not exist in the given
+     * <code>revision</code>.
+     * <p>
+     * <b>Note:</b> If the server doesn't support retrieval of
+     * mergeinfo (which can happen even for file:// URLs, if the
+     * repository itself hasn't been upgraded), an unsupported feature
+     * exception is thrown in preference to any other error that might
+     * otherwise be returned.
+     *
+     * @param revision The revision to look for <code>paths</code>
+     *                 in. Defaults to the youngest revision when
+     *                 {@link Revision.SVN_INVALID_REVNUM}.
+     * @param inherit Indicates whether explicit, explicit or
+     *                inherited, or only inherited mergeinfo for
+     *                <code>paths</code> is retrieved.
+     * @param includeDescendants When <code>true</code>, additionally
+     *        return the mergeinfo for any descendant of any element
+     *        of <code>paths</code> which has the mergeinfo explicitly
+     *        set on it.  (Note that inheritance is only taken into
+     *        account for the elements in <code>paths</code>;
+     *        descendants of the elements in <code>paths</code> which
+     *        get their mergeinfo via inheritance are not included.)
+     *
+     * @return A dictionary of {@link Mergeinfo} objects for the given
+     *         <code>paths</code>, or <code>null</code> if no
+     *         mergeinfo is available..
+     * @throws ClientException
+     */
+    Map<String, Mergeinfo> getMergeinfo(Iterable<String> paths, long revision,
+                                        Mergeinfo.Inheritance inherit,
+                                        boolean includeDescendants)
+            throws ClientException;
+
     // TODO: update
     // TODO: switch
 

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteStatus.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteStatus.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteStatus.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/RemoteStatus.java Fri Jul  5 14:42:40 2013
@@ -58,34 +58,130 @@ public interface RemoteStatus
      * @param relativePath The session-relative path of the directory.
      * @param childrenModified The directory contents changed.
      * @param propsModified The directory's properties changed.
+     * @param nodeInfo Additional information about the modified directory.
      */
     void modifiedDirectory(String relativePath,
                            boolean childrenModified,
-                           boolean propsModified);
+                           boolean propsModified,
+                           Entry nodeInfo);
 
     /**
      * A file was modified.
      * @param relativePath The session-relative path of the directory.
      * @param textModified The file contents changed.
      * @param propsModified The file's properties changed.
+     * @param nodeInfo Additional information about the modified file.
      */
     void modifiedFile(String relativePath,
                       boolean textModified,
-                      boolean propsModified);
+                      boolean propsModified,
+                      Entry nodeInfo);
 
     /**
      * A symbolic link was modified.
      * @param relativePath The session-relative path of the symlink.
      * @param textModified The link target changed.
      * @param propsModified The symlink's properties changed.
+     * @param nodeInfo Additional information about the modified symlink.
      */
     void modifiedSymlink(String relativePath,
                          boolean targetModified,
-                         boolean propsModified);
+                         boolean propsModified,
+                         Entry nodeInfo);
+
 
     /**
      * An entry was deleted.
      * @param relativePath The session-relative path of the entry.
      */
     void deleted(String relativePath);
+
+
+    /**
+     * Contains additional information related to a modification or
+     * deletion event.
+     */
+    public static class Entry
+        implements Comparable<Entry>, java.io.Serializable
+    {
+        // Update the serialVersionUID when there is a incompatible
+        // change made to this class.
+        private static final long serialVersionUID = 1L;
+
+        private String uuid;    // The UUID of the repository
+        private String author;  // The author of the last change
+        private long revision;  // Committed revision number
+        private long timestamp; // Commit timestamp (milliseconds from epoch)
+
+        public Entry(String uuid, String author, long revision, long timestamp)
+        {
+            this.uuid = uuid;
+            this.author = author;
+            this.revision = revision;
+            this.timestamp = timestamp;
+        }
+
+        /** @return The UUID of the repository that the node belongs to. */
+        public String getUuid() { return uuid; }
+
+        /** @return The author (committer) of the change. */
+        public String getLastAuthor() { return author; }
+
+        /** @return The revision number in with the change was committed. */
+        public long getCommittedRevision() { return revision; }
+
+        /**
+         * @return The timestamp, in milliseconds from the epoch, of
+         * the committed revision.
+         */
+        public long getCommittedTimestamp() { return timestamp; }
+
+        /** Implementation of interface {@link java.lang.Comparable}. */
+        public int compareTo(Entry that)
+        {
+            if (this == that)
+                return 0;
+
+            int cmp = uuid.compareTo(that.uuid);
+            if (cmp == 0) {
+                cmp = author.compareTo(that.author);
+                if (cmp == 0) {
+                    cmp = (revision < that.revision ? 1
+                           : (revision > that.revision ? -1 : 0));
+                    if (cmp == 0)
+                        cmp = (timestamp < that.timestamp ? 1
+                               : (timestamp > that.timestamp ? -1 : 0));
+                }
+            }
+            return cmp;
+        }
+
+        @Override
+        public boolean equals(Object entry)
+        {
+            if (this == entry)
+                return true;
+            if (!super.equals(entry) || getClass() != entry.getClass())
+                return false;
+
+            final Entry that = (Entry)entry;
+            return (this.uuid == that.uuid
+                    && this.author == that.author
+                    && this.revision == that.revision
+                    && this.timestamp == that.timestamp);
+        }
+
+        @Override
+        public int hashCode()
+        {
+            final int factor = 33;
+            int hash = ((uuid == null) ? 0 : uuid.hashCode());
+            hash = factor * hash + ((author == null) ? 0 : author.hashCode());
+            hash = factor * hash + (int)(revision >> 32) & 0xffffffff;
+            hash = factor * hash + (int)revision & 0xffffffff;
+            hash = factor * hash + (int)(timestamp >> 32) & 0xffffffff;
+            hash = factor * hash + (int)timestamp & 0xffffffff;
+            return hash;
+        }
+    }
 }

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java Fri Jul  5 14:42:40 2013
@@ -150,16 +150,18 @@ public class RemoteSession extends JNIOb
                              Map<String, byte[]> properties)
             throws ClientException
     {
-        if (direntFields <= 0 && direntFields != DirEntry.Fields.all)
-            throw new IllegalArgumentException(
-                "direntFields must be positive or DirEntry.Fields.all");
         maybe_clear(dirents);
         maybe_clear(properties);
         return nativeGetDirectory(revision, path,
                                   direntFields, dirents, properties);
     }
 
-    // TODO: getMergeinfo
+    public native Map<String, Mergeinfo>
+        getMergeinfo(Iterable<String> paths, long revision,
+                     Mergeinfo.Inheritance inherit,
+                     boolean includeDescendants)
+            throws ClientException;
+
     // TODO: update
     // TODO: switch
 

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/StatusEditor.java Fri Jul  5 14:42:40 2013
@@ -29,7 +29,11 @@ import org.apache.subversion.javahl.call
 import org.apache.subversion.javahl.ISVNEditor;
 
 import java.util.Map;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
 import java.io.InputStream;
+import java.nio.charset.Charset;
 
 /**
  * Package-private editor implementation that converts an editor drive
@@ -105,7 +109,8 @@ class StatusEditor implements ISVNEditor
         //DEBUG:System.err.println("  [J] StatusEditor.alterDirectory");
         checkState();
         receiver.modifiedDirectory(relativePath, (children != null),
-                                   props_changed(properties));
+                                   props_changed(properties),
+                                   make_entry(properties));
     }
 
     public void alterFile(String relativePath,
@@ -118,7 +123,8 @@ class StatusEditor implements ISVNEditor
         checkState();
         receiver.modifiedFile(relativePath,
                               (checksum != null && contents != null),
-                              props_changed(properties));
+                              props_changed(properties),
+                              make_entry(properties));
     }
 
     public void alterSymlink(String relativePath,
@@ -129,7 +135,8 @@ class StatusEditor implements ISVNEditor
         //DEBUG:System.err.println("  [J] StatusEditor.alterSymlink");
         checkState();
         receiver.modifiedSymlink(relativePath, (target != null),
-                                 props_changed(properties));
+                                 props_changed(properties),
+                                 make_entry(properties));
     }
 
     public void delete(String relativePath, long revision)
@@ -173,6 +180,58 @@ class StatusEditor implements ISVNEditor
     }
 
     /*
+     * Construct a RemoteStatus.Entry record from the given properties.
+     */
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+    private static final SimpleTimeZone UTC =
+        new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC");
+    private static final String entryprop_uuid = "svn:entry:uuid";
+    private static final String entryprop_author = "svn:entry:last-author";
+    private static final String entryprop_revision = "svn:entry:committed-rev";
+    private static final String entryprop_timestamp = "svn:entry:committed-date";
+    private final GregorianCalendar entry_calendar =
+        new GregorianCalendar(UTC, Locale.ROOT);
+
+    // FIXME: Room for improvement here. There are likely to be a lot
+    // of duplicate entries and we should be able to avoid parsing the
+    // duplicates all over again. Need a map <raw data> -> Entry to
+    // just look up the entries instead of parsing them.
+    private final RemoteStatus.Entry make_entry(Map<String, byte[]> properties)
+    {
+        final byte[] raw_uuid = properties.get(entryprop_uuid);
+        final byte[] raw_author = properties.get(entryprop_author);
+        final byte[] raw_revision = properties.get(entryprop_revision);
+        final byte[] raw_timestamp = properties.get(entryprop_timestamp);
+
+        long parsed_timestamp = -1;
+        if (raw_timestamp != null)
+        {
+            // Parse: 2013-07-04T23:17:59.128366Z
+            final String isodate = new String(raw_timestamp, UTF8);
+
+            final int year = Integer.valueOf(isodate.substring(0,4), 10);
+            final int month = Integer.valueOf(isodate.substring(5,7), 10);
+            final int day = Integer.valueOf(isodate.substring(8,10), 10);
+            final int hour = Integer.valueOf(isodate.substring(11,13), 10);
+            final int minute = Integer.valueOf(isodate.substring(14,16), 10);
+            final int second = Integer.valueOf(isodate.substring(17,19), 10);
+            final int micro = Integer.valueOf(isodate.substring(20,26), 10);
+            entry_calendar.set(year, month, day, hour, minute, second);
+
+             // Use integer rounding to add milliseconds
+            parsed_timestamp =
+                (1000 * entry_calendar.getTimeInMillis() + micro + 500) / 1000;
+        }
+
+        return new RemoteStatus.Entry(
+            (raw_uuid == null ? null : new String(raw_uuid, UTF8)),
+            (raw_author == null ? null : new String(raw_author, UTF8)),
+            (raw_revision == null ? Revision.SVN_INVALID_REVNUM
+             : Long.valueOf(new String(raw_revision, UTF8), 10)),
+            parsed_timestamp);
+    }
+
+    /*
      * Filter entry props from the incoming properties
      */
     private static final String wcprop_prefix = "svn:wc:";

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/Mergeinfo.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/Mergeinfo.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/Mergeinfo.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/Mergeinfo.java Fri Jul  5 14:42:40 2013
@@ -69,6 +69,31 @@ public class Mergeinfo implements java.i
     }
 
     /**
+     * The three ways to request mergeinfo affecting a given path
+     * in {@link org.apache.subversion.javahl.ISVNRemote#getMergeinfo}.
+     * @since 1.9
+     */
+    public static enum Inheritance
+    {
+        /** Explicit mergeinfo only. */
+        explicit,
+
+        /**
+         * Explicit mergeinfo, or if that doesn't exist, the inherited
+         * mergeinfo from a target's nearest (path-wise, not history-wise)
+         * ancestor.
+         */
+        inherited,
+
+        /**
+         * Mergeinfo inherited from a target's nearest (path-wise,
+         * not history-wise) ancestor, regardless of whether target
+         * has explicit mergeinfo.
+         */
+        nearest_ancestor;
+    }
+
+    /**
      * Add one or more RevisionRange objects to merge info. If the
      * merge source is already stored, the list of revisions is
      * replaced.

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/RevisionRange.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/RevisionRange.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/RevisionRange.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/RevisionRange.java Fri Jul  5 14:42:40 2013
@@ -36,25 +36,35 @@ public class RevisionRange implements Co
     // http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf
     // http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html#6678
     // http://java.sun.com/javase/6/docs/platform/serialization/spec/version.html#6678
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 2L;
 
     private Revision from;
     private Revision to;
+    private boolean inheritable;
 
     /**
      * Creates a new instance.  Called by native library.
      */
-    @SuppressWarnings("unused")
-    private RevisionRange(long from, long to)
+    protected RevisionRange(long from, long to, boolean inheritable)
     {
         this.from = Revision.getInstance(from);
         this.to = Revision.getInstance(to);
+        this.inheritable = inheritable;
+    }
+
+    /** @since 1.9 */
+    public RevisionRange(Revision from, Revision to, boolean inheritable)
+    {
+        this.from = from;
+        this.to = to;
+        this.inheritable = inheritable;
     }
 
     public RevisionRange(Revision from, Revision to)
     {
         this.from = from;
         this.to = to;
+        this.inheritable = true;
     }
 
     /**
@@ -70,6 +80,11 @@ public class RevisionRange implements Co
             return;
         }
 
+        this.inheritable = !revisionElement.endsWith("*");
+        if (!this.inheritable)
+            revisionElement =
+                revisionElement.substring(0, revisionElement.length() - 1);
+
         int hyphen = revisionElement.indexOf('-');
         if (hyphen > 0)
         {
@@ -113,14 +128,20 @@ public class RevisionRange implements Co
         return to;
     }
 
+    public boolean isInheritable()
+    {
+        return inheritable;
+    }
+
     public String toString()
     {
         if (from != null && to != null)
         {
-            if (from.equals(to))
-                return from.toString();
-            else
-                return from.toString() + '-' + to.toString();
+            String rep = (from.equals(to) ? from.toString()
+                          : from.toString() + '-' + to.toString());
+            if (!inheritable)
+                return rep + '*';
+            return rep;
         }
         return super.toString();
     }
@@ -138,7 +159,7 @@ public class RevisionRange implements Co
     public int hashCode()
     {
         final int prime = 31;
-        int result = 1;
+        int result = (inheritable ? 1 : 2);
         result = prime * result + ((from == null) ? 0 : from.hashCode());
         result = prime * result + ((to == null) ? 0 : to.hashCode());
         return result;
@@ -178,10 +199,12 @@ public class RevisionRange implements Co
             return false;
         }
 
-        return true;
+        return (inheritable == other.inheritable);
     }
 
     /**
+     * <b>Note:</b> Explicitly ignores inheritable state.
+     *
      * @param range The RevisionRange to compare this object to.
      */
     public int compareTo(RevisionRange range)

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Fri Jul  5 14:42:40 2013
@@ -251,16 +251,17 @@ public class BasicTests extends SVNTests
     public void testMergeinfoParser() throws Throwable
     {
         String mergeInfoPropertyValue =
-            "/trunk:1-300,305,307,400-405\n/branches/branch:308-400";
+            "/trunk:1-300,305*,307,400-405*\n" +
+            "/branches/branch:308-400";
         Mergeinfo info = new Mergeinfo(mergeInfoPropertyValue);
         Set<String> paths = info.getPaths();
         assertEquals(2, paths.size());
         List<RevisionRange> trunkRange = info.getRevisionRange("/trunk");
         assertEquals(4, trunkRange.size());
         assertEquals("1-300", trunkRange.get(0).toString());
-        assertEquals("305", trunkRange.get(1).toString());
+        assertEquals("305*", trunkRange.get(1).toString());
         assertEquals("307", trunkRange.get(2).toString());
-        assertEquals("400-405", trunkRange.get(3).toString());
+        assertEquals("400-405*", trunkRange.get(3).toString());
         List<RevisionRange> branchRange =
             info.getRevisionRange("/branches/branch");
         assertEquals(1, branchRange.size());

Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1500026&r1=1500025&r2=1500026&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java Fri Jul  5 14:42:40 2013
@@ -30,6 +30,7 @@ import org.apache.subversion.javahl.type
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 import java.util.Map;
 import java.util.HashMap;
@@ -793,6 +794,7 @@ public class SVNRemoteTests extends SVNT
             public boolean textChanged = false;
             public boolean propsChanged = false;
             public boolean deleted = false;
+            public Entry info = null;
 
             StatInfo(String relpath, char kind, boolean added)
             {
@@ -802,55 +804,106 @@ public class SVNRemoteTests extends SVNT
             }
 
             StatInfo(String relpath, char kind,
-                     boolean textChanged, boolean propsChanged)
+                     boolean textChanged, boolean propsChanged,
+                     Entry info)
             {
                 this.relpath = relpath;
                 this.kind = kind;
                 this.textChanged = textChanged;
                 this.propsChanged = propsChanged;
+                this.info = info;
             }
         }
 
+        private boolean debug;
+
+        public RemoteStatusReceiver()
+        {
+            this.debug = false;
+        }
+
+        public RemoteStatusReceiver(boolean debug)
+        {
+            this.debug = debug;
+        }
+
         public ArrayList<StatInfo> status = new ArrayList<StatInfo>();
 
         public void addedDirectory(String relativePath)
         {
+            if (debug)
+                System.err.println("RemoteStatus:  A   (dir)  " +
+                                   relativePath);
             status.add(new StatInfo(relativePath, 'D', true));
         }
 
         public void addedFile(String relativePath)
         {
+            if (debug)
+                System.err.println("RemoteStatus:  A   (file) "
+                                   + relativePath);
             status.add(new StatInfo(relativePath, 'F', true));
         }
 
         public void addedSymlink(String relativePath)
         {
+            if (debug)
+                System.err.println("RemoteStatus:  A   (link) "
+                                   + relativePath);
             status.add(new StatInfo(relativePath, 'L', true));
         }
 
         public void modifiedDirectory(String relativePath,
-                                      boolean childrenModified, boolean propsModified)
-        {
+                                      boolean childrenModified,
+                                      boolean propsModified,
+                                      Entry nodeInfo)
+        {
+            if (debug)
+                System.err.println("RemoteStatus:  " +
+                                   (childrenModified ? 'M' : '_') +
+                                   (propsModified ? 'M' : '_') +
+                                   "  (dir)  " + relativePath);
             status.add(new StatInfo(relativePath, 'D',
-                                    childrenModified, propsModified));
+                                    childrenModified, propsModified,
+                                    nodeInfo));
         }
 
         public void modifiedFile(String relativePath,
-                                 boolean textModified, boolean propsModified)
-        {
+                                 boolean textModified,
+                                 boolean propsModified,
+                                 Entry nodeInfo)
+        {
+            if (debug)
+                System.err.println("RemoteStatus:  " +
+                                   (textModified ? 'M' : '_') +
+                                   (propsModified ? 'M' : '_') +
+                                   "  (file) " + relativePath);
             status.add(new StatInfo(relativePath, 'F',
-                                    textModified, propsModified));
+                                    textModified, propsModified,
+                                    nodeInfo));
         }
 
         public void modifiedSymlink(String relativePath,
-                                    boolean targetModified, boolean propsModified)
-        {
+                                    boolean targetModified,
+                                    boolean propsModified,
+                                    Entry nodeInfo)
+        {
+            if (debug)
+                System.err.println("RemoteStatus:  " +
+                                   (targetModified ? 'M' : '_') +
+                                   (propsModified ? 'M' : '_') +
+                                   "  (link) " + relativePath);
             status.add(new StatInfo(relativePath, 'L',
-                                    targetModified, propsModified));
+                                    targetModified, propsModified,
+                                    nodeInfo));
+
         }
 
         public void deleted(String relativePath)
         {
+            if (debug)
+                System.err.println("RemoteStatus:  D          "
+                                   + relativePath);
             status.add(new StatInfo(relativePath, ' ', false));
         }
     }
@@ -899,5 +952,99 @@ public class SVNRemoteTests extends SVNT
         assertEquals('F', mod.kind);
         assertEquals(false, mod.textChanged);
         assertEquals(true, mod.propsChanged);
+        assertEquals(false, mod.deleted);
+        assertEquals(2, mod.info.getCommittedRevision());
+    }
+
+    public void testDeletedStatus() throws Exception
+    {
+        ISVNRemote session = getSession();
+
+        CommitMessageCallback cmcb = new CommitMessageCallback() {
+                public String getLogMessage(Set<CommitItem> x) {
+                    return "Delete A/mu";
+                }
+            };
+        HashSet<String> paths = new HashSet<String>(1);
+        paths.add(getTestRepoUrl() + "/A/mu");
+        client.remove(paths, false, false, null, cmcb, null);
+
+        RemoteStatusReceiver receiver = new RemoteStatusReceiver();
+        ISVNReporter rp = session.status(null, Revision.SVN_INVALID_REVNUM,
+                                         Depth.infinity, receiver);
+        try {
+            rp.setPath("", 1, Depth.infinity, false, null);
+            assertEquals(2, rp.finishReport());
+        } finally {
+            rp.dispose();
+        }
+        assertEquals(3, receiver.status.size());
+        RemoteStatusReceiver.StatInfo mod = receiver.status.get(2);
+        assertEquals("A/mu", mod.relpath);
+        assertEquals(' ', mod.kind);
+        assertEquals(false, mod.textChanged);
+        assertEquals(false, mod.propsChanged);
+        assertEquals(true, mod.deleted);
+    }
+
+    public void testTrivialMergeinfo() throws Exception
+    {
+        ISVNRemote session = getSession();
+        ArrayList<String> paths = new ArrayList<String>(1);
+        paths.add("");
+
+        Map<String, Mergeinfo> catalog =
+            session.getMergeinfo(paths, 1L, Mergeinfo.Inheritance.explicit,
+                                 false);
+        assertEquals(null, catalog);
+    }
+
+    public void testBranchMergeinfo() throws Exception
+    {
+        CommitMessageCallback cmcb = new CommitMessageCallback() {
+                public String getLogMessage(Set<CommitItem> x) {
+                    return "testBranchMergeinfo";
+                }
+            };
+
+        ISVNRemote session = getSession();
+
+        // Create a branch
+        ArrayList<CopySource> dirA = new ArrayList<CopySource>(1);
+        dirA.add(new CopySource(getTestRepoUrl() + "/A",
+                                Revision.HEAD, Revision.HEAD));
+        client.copy(dirA, getTestRepoUrl() + "/Abranch",
+                    false, false, true, null, cmcb, null);
+
+        // Check mergeinfo on new branch
+        ArrayList<String> paths = new ArrayList<String>(1);
+        paths.add("Abranch");
+        Map<String, Mergeinfo> catalog =
+            session.getMergeinfo(paths, 2L, Mergeinfo.Inheritance.explicit,
+                                 false);
+        assertEquals(null, catalog);
+
+        // Modify source and merge to branch
+        client.propertySetRemote(getTestRepoUrl() + "/A/D/gamma",
+                                 2L, "foo", "bar".getBytes(), cmcb,
+                                 false, null, null);
+        client.update(thisTest.getWCPathSet(), Revision.HEAD, Depth.infinity,
+                      false, false, true, false);
+        client.merge(getTestRepoUrl() + "/A", Revision.HEAD, null,
+                     thisTest.getWCPath() + "/Abranch", false, Depth.infinity,
+                     false, false, false, false);
+        client.commit(thisTest.getWCPathSet(), Depth.infinity, false, false,
+                      null, null, cmcb, null);
+
+        // Check inherited mergeinfo on updated branch
+        paths.set(0, "Abranch/mu");
+        catalog = session.getMergeinfo(paths, 4L,
+                                       Mergeinfo.Inheritance.nearest_ancestor,
+                                       false);
+        assertEquals(1, catalog.size());
+        List<RevisionRange> ranges =
+            catalog.get("Abranch/mu").getRevisions("/A/mu");
+        assertEquals(1, ranges.size());
+        assertEquals("1-3", ranges.get(0).toString());
     }
 }