You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/06/25 18:43:37 UTC

svn commit: r1496533 - in /subversion/trunk: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/ subversion/bindings/javahl/tests/org/apa...

Author: brane
Date: Tue Jun 25 16:43:36 2013
New Revision: 1496533

URL: http://svn.apache.org/r1496533
Log:
Add a load of boilerplate onto JavaHL's RA commit editor.

* build.conf (private-built-includes): Add javah's generated CommitEditor.h.

[in subversion/bindings/javahl/src/org/apache/subversion/javahl]
* ISVNRemote.java (ISVNRemote.getCommitEditor): Update interface and docstring.
  (ISVNRemote.status): Renamed from ISVNRemote.doStatus.
  Update boilerplate comments.
* remote/RemoteSession.java (RemoteSession.editor): Replaces set of editors.
  (ISVNRemote.dispose): Update, only one editor at a time can be active.
  (ISVNRemote.getCommitEditor): Update implementation.
  (RemoteSession.disposeEditor): New; called by CommitEditor.dispose.
  (ISVNRemote.status): Renamed from ISVNRemote.doStatus.
  Update boilerplate comments.
* remote/CommitEditor.java: Implement all unimplemented ISVNEditor methods
   as wrappers around native methods.
  (CommitEditor.CommitEditor): Add RemoteSession parameter ...
  (CommitEditor.session): ... and store it here.
  (CommitEditor.finalize): Add native method.
  
[in subversion/bindings/javahl/native]
* CommitEditor.h, CommitEditor.cpp,
  LockTokenTable.h, LockTokenTable.cpp,
  org_apache_subversion_javahl_remote_CommitEditor.cpp: New files.
* RemoteSession.h (RemoteSession): Make CommitEditor a friend.
  (RemoteSession::status): Renamed from RemoteSession::doStatus.
  Update boilerplate comments.
* RemoteSession.cpp
  (RemoteSession::status): Renamed from RemoteSession::doStatus.
  Update boilerplate comments.
* org_apache_subversion_javahl_remote_RemoteSession.cpp
  (Java_org_apache_subversion_javahl_remote_RemoteSession_nativeDispose):
   Update JNIEntry statement;
  (Java_org_apache_subversion_javahl_remote_RemoteSession_status):
   Renamed from ..._doStatus.
  Update boilerplate comments.

[in subversion/bindings/javahl/tests/org/apache/subversion/javahl]
* SVNRemoteTests.java
  (SVNRemoteTests.testGetCommitEditor,
   SVNRemoteTests.testDisposeCommitEditor): Update test cases.
  (SVNRemoteTests.testChangeRevpropAtomic): Use the new
   ClientException.getAllMessages method.

Added:
    subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp
    subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h
    subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp
    subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h
    subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp
Modified:
    subversion/trunk/build.conf
    subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp
    subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h
    subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java

Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Tue Jun 25 16:43:36 2013
@@ -69,6 +69,7 @@ private-built-includes =
         subversion/bindings/javahl/include/org_apache_subversion_javahl_callback_UserPasswordCallback.h
         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_remote_CommitEditor.h
 
 
 test-scripts =

Added: subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp?rev=1496533&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp Tue Jun 25 16:43:36 2013
@@ -0,0 +1,349 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file CommitEditor.cpp
+ * @brief Implementation of the class CommitEditor
+ */
+
+#include "CommitEditor.h"
+#include "LockTokenTable.h"
+#include "RevpropTable.h"
+#include "RemoteSession.h"
+
+#include "svn_delta.h"
+#include "private/svn_editor.h"
+#include "svn_private_config.h"
+
+CommitEditor*
+CommitEditor::getCppObject(jobject jthis)
+{
+  static jfieldID fid = 0;
+  jlong cppAddr = SVNBase::findCppAddrForJObject(
+      jthis, &fid, JAVA_PACKAGE"/remote/CommitEditor");
+  return (cppAddr == 0 ? NULL : reinterpret_cast<CommitEditor*>(cppAddr));
+}
+
+jlong
+CommitEditor::createInstance(jobject jsession,
+                             jobject jrevprops,
+                             jobject jcommit_callback,
+                             jobject jlock_tokens,
+                             jboolean jkeep_locks)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session, 0);
+
+  CommitEditor* editor = new CommitEditor(session->m_session,
+                                          jrevprops, jcommit_callback,
+                                          jlock_tokens, bool(jkeep_locks));
+  if (JNIUtil::isJavaExceptionThrown())
+    {
+      delete editor;
+      return 0;
+    }
+  return editor->getCppAddr();
+}
+
+
+CommitEditor::CommitEditor(svn_ra_session_t* session,
+                           jobject jrevprops, jobject jcommit_callback,
+                           jobject jlock_tokens, bool keep_locks)
+  : m_valid(false),
+    m_callback(jcommit_callback),
+    m_editor(NULL),
+    m_extra_baton(NULL)
+{
+  RevpropTable revprops(jrevprops, true);
+  LockTokenTable lock_tokens(jlock_tokens);
+
+  SVN::Pool subPool(pool);
+  const svn_delta_editor_t* delta_editor = NULL;
+  void* delta_edit_baton = NULL;
+  SVN_JNI_ERR(svn_ra_get_commit_editor3(
+                  session, &delta_editor, &delta_edit_baton,
+                  revprops.hash(subPool, false),
+                  m_callback.callback, &m_callback,
+                  lock_tokens.hash(subPool, true),
+                  keep_locks, pool.getPool()),
+              );
+
+//  SVN_JNI_ERR(svn_delta__editor_from_delta(
+//                  &m_editor, &m_extra_baton,
+//
+//                  svn_delta__unlock_func_t *unlock_func,
+//                  void **unlock_baton,
+//
+//                  delta_editor, delta_edit_baton,
+//
+//                  svn_boolean_t *send_abs_paths,
+//                  const char *repos_root,
+//                  const char *base_relpath,
+//                  svn_cancel_func_t cancel_func,
+//                  void *cancel_baton,
+//                  svn_delta_fetch_kind_func_t fetch_kind_func,
+//                  void *fetch_kind_baton,
+//                  svn_delta_fetch_props_func_t fetch_props_func,
+//                  void *fetch_props_baton,
+//
+//                  pool.getPool(),    // result_pool
+//                  subpool.getPool()) // scratch_pool
+//              );
+
+  m_valid = true;
+}
+
+CommitEditor::~CommitEditor() {}
+
+void CommitEditor::dispose(jobject jthis)
+{
+  //if (m_valid)
+  //  abort();
+
+  static jfieldID fid = 0;
+  SVNBase::dispose(jthis, &fid, JAVA_PACKAGE"/remote/CommitEditor");
+}
+
+namespace {
+void throw_editor_inactive()
+{
+  JNIEnv *env = JNIUtil::getEnv();
+
+  jclass clazz = env->FindClass("java/lang/IllegalStateException");
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  static jmethodID ctor_mid = 0;
+  if (0 == ctor_mid)
+    {
+      ctor_mid = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;)V");
+      if (JNIUtil::isJavaExceptionThrown())
+        return;
+    }
+
+  jstring jmsg = JNIUtil::makeJString(_("The editor is not active"));
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  jobject jexception = env->NewObject(clazz, ctor_mid, jmsg);
+  if (JNIUtil::isJavaExceptionThrown())
+    return;
+
+  env->Throw((jthrowable)jexception);
+}
+} // anonymous namespace
+
+
+void CommitEditor::addDirectory(jobject jsession, jstring jrelpath,
+                                jobject jchildren, jobject jproperties,
+                                jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::addFile(jobject jsession, jstring jrelpath,
+                           jobject jchecksum, jobject jcontents,
+                           jobject jproperties,
+                           jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::addSymlink(jobject jsession, jstring jrelpath,
+                              jstring jtarget, jobject jproperties,
+                              jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::addAbsent(jobject jsession, jstring jrelpath,
+                             jobject jkind, jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::alterDirectory(jobject jsession,
+                                  jstring jrelpath, jlong jrevision,
+                                  jobject jchildren, jobject jproperties)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::alterFile(jobject jsession,
+                             jstring jrelpath, jlong jrevision,
+                             jobject jchecksum, jobject jcontents,
+                             jobject jproperties)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::alterSymlink(jobject jsession,
+                                jstring jrelpath, jlong jrevision,
+                                jstring jtarget, jobject jproperties)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::remove(jobject jsession, jstring jrelpath, jlong jrevision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::copy(jobject jsession,
+                        jstring jsrc_relpath, jlong jsrc_revision,
+                        jstring jdst_relpath, jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::move(jobject jsession,
+                        jstring jsrc_relpath, jlong jsrc_revision,
+                        jstring jdst_relpath, jlong jreplaces_revision)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::rotate(jobject jsession, jobject jelements)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+}
+
+void CommitEditor::complete(jobject jsession)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+
+  // do stuff
+
+  m_valid = false;
+}
+
+void CommitEditor::abort(jobject jsession)
+{
+  RemoteSession* session = RemoteSession::getCppObject(jsession);
+  CPPADDR_NULL_PTR(session,);
+  SVN_JNI_ERR(session->m_context->checkCancel(session->m_context),);
+
+  if (!m_valid || 1/*FIXME:*/)
+    {
+      throw_editor_inactive();
+      return;
+    }
+
+  // do stuff
+
+  m_valid = false;
+}

Added: subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h?rev=1496533&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h (added)
+++ subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h Tue Jun 25 16:43:36 2013
@@ -0,0 +1,102 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file CommitEditor.h
+ * @brief Interface of the class CommitEditor
+ */
+
+#ifndef JAVAHL_COMMIT_EDITOR_H
+#define JAVAHL_COMMIT_EDITOR_H
+
+#include <jni.h>
+
+#include "svn_ra.h"
+
+#include "JNIUtil.h"
+#include "SVNBase.h"
+#include "CommitCallback.h"
+
+// Forward-declare the currently private EV2 editor structs.
+struct svn_editor_t;
+struct svn_delta__extra_baton;
+
+/*
+ * This class wraps an EV2 commit editor.
+ */
+class CommitEditor : public SVNBase
+{
+public:
+  static CommitEditor* getCppObject(jobject jthis);
+  static jlong createInstance(jobject jsession,
+                              jobject jrevprops,
+                              jobject jcommit_callback,
+                              jobject jlock_tokens,
+                              jboolean jkeep_locks);
+  virtual ~CommitEditor();
+
+  virtual void dispose(jobject jthis);
+
+  void addDirectory(jobject jsession, jstring jrelpath,
+                    jobject jchildren, jobject jproperties,
+                    jlong jreplaces_revision);
+  void addFile(jobject jsession, jstring jrelpath,
+               jobject jchecksum, jobject jcontents,
+               jobject jproperties,
+               jlong jreplaces_revision);
+  void addSymlink(jobject jsession, jstring jrelpath,
+                  jstring jtarget, jobject jproperties,
+                  jlong jreplaces_revision);
+  void addAbsent(jobject jsession, jstring jrelpath,
+                 jobject jkind, jlong jreplaces_revision);
+  void alterDirectory(jobject jsession,
+                      jstring jrelpath, jlong jrevision,
+                      jobject jchildren, jobject jproperties);
+  void alterFile(jobject jsession,
+                 jstring jrelpath, jlong jrevision,
+                 jobject jchecksum, jobject jcontents,
+                 jobject jproperties);
+  void alterSymlink(jobject jsession,
+                    jstring jrelpath, jlong jrevision,
+                    jstring jtarget, jobject jproperties);
+  void remove(jobject jsession, jstring jrelpath, jlong jrevision);
+  void copy(jobject jsession,
+            jstring jsrc_relpath, jlong jsrc_revision,
+            jstring jdst_relpath, jlong jreplaces_revision);
+  void move(jobject jsession,
+            jstring jsrc_relpath, jlong jsrc_revision,
+            jstring jdst_relpath, jlong jreplaces_revision);
+  void rotate(jobject jsession, jobject jelements);
+  void complete(jobject jsession);
+  void abort(jobject jsession);
+
+private:
+  CommitEditor(svn_ra_session_t* session,
+               jobject jrevprops, jobject jcommit_callback,
+               jobject jlock_tokens, bool keep_locks);
+
+  bool m_valid;
+  CommitCallback m_callback;
+  svn_editor_t* m_editor;
+  svn_delta__extra_baton* m_extra_baton;
+};
+
+#endif // JAVAHL_COMMIT_EDITOR_H

Added: subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp?rev=1496533&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp Tue Jun 25 16:43:36 2013
@@ -0,0 +1,114 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file LockTokenTable.cpp
+ * @brief Implementation of the class LockTokenTable
+ */
+
+#include "LockTokenTable.h"
+#include "JNIUtil.h"
+#include "JNIStringHolder.h"
+#include "Array.h"
+#include <apr_hash.h>
+
+LockTokenTable::~LockTokenTable()
+{
+  if (m_jlock_tokens)
+    JNIUtil::getEnv()->DeleteLocalRef(m_jlock_tokens);
+}
+
+apr_hash_t*
+LockTokenTable::hash(const SVN::Pool &pool, bool null_if_empty)
+{
+  if (m_lock_tokens.size() == 0 && null_if_empty)
+    return NULL;
+
+  apr_pool_t* result_pool = pool.getPool();
+  apr_hash_t* lock_table = apr_hash_make(result_pool);
+
+  for (lock_tokens_t::const_iterator it = m_lock_tokens.begin();
+       it != m_lock_tokens.end(); ++it)
+    {
+      const char *path = apr_pstrdup(result_pool, it->first.c_str());
+      const char *token = apr_pstrdup(result_pool, it->second.c_str());
+      apr_hash_set(lock_table, path, APR_HASH_KEY_STRING, token);
+    }
+
+  return lock_table;
+}
+
+LockTokenTable::LockTokenTable(jobject jlock_tokens)
+  : m_jlock_tokens(jlock_tokens)
+{
+
+  if (jlock_tokens != NULL)
+    {
+      JNIEnv *env = JNIUtil::getEnv();
+
+      jclass lock_cls = env->FindClass(JAVA_PACKAGE"/types/Lock");
+      if (JNIUtil::isExceptionThrown())
+        return;
+
+      static jmethodID getPath_mid = 0;
+      if (0 == getPath_mid)
+        {
+          getPath_mid = env->GetMethodID(lock_cls, "getPath",
+                                         "()Ljava/lang/String;");
+          if (JNIUtil::isExceptionThrown())
+            return;
+        }
+
+      static jmethodID getToken_mid = 0;
+      if (0 == getToken_mid)
+        {
+          getToken_mid = env->GetMethodID(lock_cls, "getToken",
+                                          "()Ljava/lang/String;");
+          if (JNIUtil::isExceptionThrown())
+            return;
+        }
+
+      std::vector<jobject> locks = Array(jlock_tokens).vector();
+      for (std::vector<jobject>::const_iterator it = locks.begin();
+           it != locks.end(); ++it)
+        {
+          jobject jpath = env->CallObjectMethod(*it, getPath_mid);
+          if (JNIUtil::isExceptionThrown())
+            return;
+          jobject jtoken = env->CallObjectMethod(*it, getToken_mid);
+          if (JNIUtil::isExceptionThrown())
+            return;
+
+          JNIStringHolder path((jstring)jpath);
+          if (JNIUtil::isExceptionThrown())
+            return;
+          JNIStringHolder token((jstring)jtoken);
+          if (JNIUtil::isExceptionThrown())
+            return;
+
+          m_lock_tokens[std::string(static_cast<const char *>(path))] =
+            std::string(static_cast<const char *>(token));
+
+          env->DeleteLocalRef(jpath);
+          env->DeleteLocalRef(jtoken);
+        }
+    }
+}

Added: subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h?rev=1496533&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h (added)
+++ subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h Tue Jun 25 16:43:36 2013
@@ -0,0 +1,50 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file LockTokenTable.h
+ * @brief Interface of the class LockTokenTable
+ */
+
+#ifndef JAVAHL_LOCK_TOKEN_TABLE_H
+#define JAVAHL_LOCK_TOKEN_TABLE_H
+
+#include <jni.h>
+#include "Pool.h"
+
+struct apr_hash_t;
+
+#include <map>
+#include <string>
+
+class LockTokenTable
+{
+ private:
+  typedef std::map<std::string, std::string> lock_tokens_t;
+  lock_tokens_t m_lock_tokens;
+  jobject m_jlock_tokens;
+ public:
+  LockTokenTable(jobject jlock_tokens);
+  ~LockTokenTable();
+  apr_hash_t *hash(const SVN::Pool &pool, bool null_if_empty = true);
+};
+
+#endif // JAVAHL_LOCK_TOKEN_TABLE_H

Modified: subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp Tue Jun 25 16:43:36 2013
@@ -617,18 +617,18 @@ RemoteSession::getDirectory(jlong jrevis
 }
 
 // TODO: getMergeinfo
-// TODO: doUpdate
-// TODO: doSwitch
+// TODO: update
+// TODO: switch
 
 jobject
-RemoteSession::doStatus(jstring jstatus_target,
-                        jlong jrevision, jobject jdepth,
-                        jobject jstatus_editor)
+RemoteSession::status(jstring jstatus_target,
+                      jlong jrevision, jobject jdepth,
+                      jobject jstatus_editor)
 {
   return NULL;
 }
 
-// TODO: doDiff
+// TODO: diff
 // TODO: getLog
 
 jobject

Modified: subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h (original)
+++ subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h Tue Jun 25 16:43:36 2013
@@ -35,6 +35,8 @@
 #include "RemoteSessionContext.h"
 #include "Prompter.h"
 
+class CommitEditor;
+
 /*
  * This class wraps Ra based operations from svn_ra.h
  */
@@ -76,12 +78,12 @@ class RemoteSession : public SVNBase
     jlong getDirectory(jlong jrevision, jstring jpath, jint jdirent_fields,
                        jobject jdirents, jobject jproperties);
     // TODO: getMergeinfo
-    // TODO: doUpdate
-    // TODO: doSwitch
-    jobject doStatus(jstring jstatus_target,
-                     jlong jrevision, jobject jdepth,
-                     jobject jstatus_editor);
-    // TODO: doDiff
+    // TODO: update
+    // TODO: switch
+    jobject status(jstring jstatus_target,
+                   jlong jrevision, jobject jdepth,
+                   jobject jstatus_editor);
+    // TODO: diff
     // TODO: getLog
     jobject checkPath(jstring jpath, jlong jrevision);
     // TODO: stat
@@ -99,6 +101,7 @@ class RemoteSession : public SVNBase
     jboolean hasCapability(jstring capability);
 
   private:
+    friend class CommitEditor;
     RemoteSession(jobject*, int retryAttempts,
                   const char* url, const char* uuid,
                   const char* configDirectory,

Added: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp?rev=1496533&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp Tue Jun 25 16:43:36 2013
@@ -0,0 +1,222 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file org_apache_subversion_javahl_remote_CommitEditor.cpp
+ * @brief Implementation of the native methods in the Java class CommitEditor
+ */
+
+#include "../include/org_apache_subversion_javahl_remote_CommitEditor.h"
+
+#include "JNIStackElement.h"
+#include "JNIUtil.h"
+#include "CommitEditor.h"
+
+#include "svn_private_config.h"
+
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_finalize(
+    JNIEnv *env, jobject jthis)
+{
+  JNIEntry(CommitEditor, finalize);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  if (editor != NULL)
+    editor->finalize();
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeDispose(
+    JNIEnv *env, jobject jthis)
+{
+  JNIEntry(CommitEditor, nativeDispose);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  if (editor != NULL)
+    editor->dispose(jthis);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeCreateInstance(
+    JNIEnv *env, jclass thisclass, jobject jsession, jobject jrevprops,
+    jobject jcommit_callback, jobject jlock_tokens, jboolean jkeep_locks)
+{
+  jobject jthis = NULL;         // Placeholder -- this is a static method
+  JNIEntry(CommitEditor, nativeCreateInstance);
+
+  return CommitEditor::createInstance(jsession, jrevprops, jcommit_callback,
+                                      jlock_tokens, jkeep_locks);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAddDirectory(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jobject jchildren, jobject jproperties,
+    jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeAddDirectory);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->addDirectory(jsession,
+                       jrelpath, jchildren, jproperties, jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAddFile(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jobject jchecksum, jobject jcontents,
+    jobject jproperties, jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeAddFile);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->addFile(jsession,
+                  jrelpath, jchecksum, jcontents, jproperties,
+                  jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAddSymlink(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jstring jtarget, jobject jproperties,
+    jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeAddSymlink);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->addSymlink(jsession,
+                     jrelpath, jtarget, jproperties, jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAddAbsent(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jobject jkind, jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeAddAbsent);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->addAbsent(jsession,
+                    jrelpath, jkind, jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAlterDirectory(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jlong jrevision, jobject jchildren, jobject jproperties)
+{
+  JNIEntry(CommitEditor, nativeAlterDirectory);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->alterDirectory(jsession,
+                         jrelpath, jrevision, jchildren, jproperties);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAlterFile(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jlong jrevision, jobject jchecksum, jobject jcontents,
+    jobject jproperties)
+{
+  JNIEntry(CommitEditor, nativeAlterFile);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->alterFile(jsession,
+                    jrelpath, jrevision, jchecksum, jcontents, jproperties);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAlterSymlink(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jlong jrevision, jstring jtarget, jobject jproperties)
+{
+  JNIEntry(CommitEditor, nativeAlterSymlink);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->alterSymlink(jsession,
+                       jrelpath, jrevision, jtarget, jproperties);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeDelete(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jrelpath, jlong jrevision)
+{
+  JNIEntry(CommitEditor, nativeDelete);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->remove(jsession, jrelpath, jrevision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeCopy(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jsrc_relpath, jlong jsrc_revision, jstring jdst_relpath,
+    jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeCopy);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->copy(jsession,
+               jsrc_relpath, jsrc_revision, jdst_relpath, jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeMove(
+    JNIEnv* env, jobject jthis, jobject jsession,
+    jstring jsrc_relpath, jlong jsrc_revision, jstring jdst_relpath,
+    jlong jreplaces_revision)
+{
+  JNIEntry(CommitEditor, nativeMove);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->move(jsession,
+               jsrc_relpath, jsrc_revision, jdst_relpath, jreplaces_revision);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeRotate(
+    JNIEnv* env, jobject jthis, jobject jsession, jobject jelements)
+{
+  JNIEntry(CommitEditor, nativeRotate);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->rotate(jsession, jelements);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeComplete(
+    JNIEnv* env, jobject jthis, jobject jsession)
+{
+  JNIEntry(CommitEditor, nativeComplete);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->complete(jsession);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_CommitEditor_nativeAbort(
+    JNIEnv* env, jobject jthis, jobject jsession)
+{
+  JNIEntry(CommitEditor, nativeAbort);
+  CommitEditor *editor = CommitEditor::getCppObject(jthis);
+  CPPADDR_NULL_PTR(editor,);
+  editor->abort(jsession);
+}

Modified: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp Tue Jun 25 16:43:36 2013
@@ -49,7 +49,7 @@ JNIEXPORT void JNICALL
 Java_org_apache_subversion_javahl_remote_RemoteSession_nativeDispose(
     JNIEnv *env, jobject jthis)
 {
-  JNIEntry(RemoteSession, dispose);
+  JNIEntry(RemoteSession, nativeDispose);
   RemoteSession *ras = RemoteSession::getCppObject(jthis);
   if (ras != NULL)
     ras->dispose(jthis);
@@ -214,11 +214,11 @@ Java_org_apache_subversion_javahl_remote
 }
 
 // TODO: getMergeinfo
-// TODO: doUpdate
-// TODO: doSwitch
+// TODO: update
+// TODO: switch
 
 JNIEXPORT jobject JNICALL
-Java_org_apache_subversion_javahl_remote_RemoteSession_doStatus(
+Java_org_apache_subversion_javahl_remote_RemoteSession_status(
     JNIEnv *env, jobject jthis, jstring jstatus_target,
     jlong jrevision, jobject jdepth, jobject jstatus_editor)
 {
@@ -226,10 +226,10 @@ Java_org_apache_subversion_javahl_remote
   RemoteSession *ras = RemoteSession::getCppObject(jthis);
   CPPADDR_NULL_PTR(ras, NULL);
 
-  return ras->doStatus(jstatus_target, jrevision, jdepth, jstatus_editor);
+  return ras->status(jstatus_target, jrevision, jdepth, jstatus_editor);
 }
 
-// TODO: doDiff
+// TODO: diff
 // TODO: getLog
 
 JNIEXPORT jobject JNICALL

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java Tue Jun 25 16:43:36 2013
@@ -28,6 +28,7 @@ import org.apache.subversion.javahl.call
 
 import java.util.Date;
 import java.util.Map;
+import java.util.Set;
 import java.io.OutputStream;
 
 /**
@@ -44,7 +45,7 @@ public interface ISVNRemote
     void dispose();
 
     /**
-     * Cancel the active operation.
+     * Cancel the active operation, including any ongoing edits.
      * @throws ClientException
      */
     void cancelOperation() throws ClientException;
@@ -156,10 +157,47 @@ public interface ISVNRemote
             throws ClientException;
 
     /**
-     * Create a commit editor instance, rooted at the current session URL.
-     * @throws ClientException
-     */
-    ISVNEditor getCommitEditor() throws ClientException;
+     * Return an editor for committing changes to the session's
+     * repository, setting the revision properties from
+     * <code>revisionProperties</code>. The revisions being committed
+     * against are passed to the editor functions. The root of the commit
+     * is the session's URL.
+     * <p>
+     * <code>revisionProperties</code> is a hash mapping property names to
+     * property values. The commit log message is expected to be in the
+     * {@link Property#REV_LOG} element.  <code>revisionProperties</code>
+     * can not contain either of {@link Property#REV_DATE} or
+     * {@link Property#REV_AUTHOR}.
+     * <p>
+     * Before {@link ISVNEditor#complete()} returns, but after the commit
+     * has succeeded, it will invoke <code>commitCallback</code> (if not
+     * <code>null</code>) with filled-in {@link CommitInfo}.  If
+     * <code>commitCallback</code> returns an error, that error will be
+     * returned from {@link ISVNEditor#complete()}, otherwise
+     * {@link ISVNEditor#complete()} will return successfully (unless it
+     * encountered an error before invoking <code>commitCallback</code>).
+     * The callback will not be called if the commit was a no-op
+     * (i.e., nothing was committed).
+     * <p>
+     * <code>lockTokens</code>, if not <code>null</code>, is a hash
+     * mapping paths (relative to the session's URL) to lock tokens.  The
+     * server checks that the correct token is provided for each
+     * committed, locked path.  <code>lockTokens</code> must live during
+     * the whole commit operation.
+     * <p>
+     * If <cpde>keepLocks</code> is <cpde>true</code>, then do not release
+     * locks on committed objects.  Else, automatically release such
+     * locks.
+     * <p>
+     * The caller may not perform any remote operations using this session
+     * before finishing the edit.
+     * @throws ClientException
+     */
+    ISVNEditor getCommitEditor(Map<String, byte[]> revisionProperties,
+                               CommitCallback commitCallback,
+                               Set<Lock> lockTokens,
+                               boolean keepLocks)
+            throws ClientException;
 
     /**
      * Fetch the contents and properties of file <code>path</code> at
@@ -242,8 +280,8 @@ public interface ISVNRemote
             throws ClientException;
 
     // TODO: getMergeinfo
-    // TODO: doUpdate
-    // TODO: doSwitch
+    // TODO: update
+    // TODO: switch
 
     /**
      * Ask for a description of the status of a working copy with
@@ -292,12 +330,12 @@ public interface ISVNRemote
      * <code>depth</code>.
      * @throws ClientException
      */
-    ISVNReporter doStatus(String statusTarget,
-                          long revision, Depth depth,
-                          ISVNEditor statusEditor)
+    ISVNReporter status(String statusTarget,
+                        long revision, Depth depth,
+                        ISVNEditor statusEditor)
             throws ClientException;
 
-    // TODO: doDiff
+    // TODO: diff
     // TODO: getLog
 
     /**

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java Tue Jun 25 16:43:36 2013
@@ -33,6 +33,7 @@ import org.apache.subversion.javahl.Clie
 import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Implementation of ISVNEditor that drives commits.
@@ -40,7 +41,11 @@ import java.util.Map;
  */
 public class CommitEditor extends JNIObject implements ISVNEditor
 {
-    public void dispose() {/* TODO */}
+    public void dispose()
+    {
+        session.disposeEditor(this);
+        nativeDispose();
+    }
 
     public void addDirectory(String relativePath,
                              Iterable<String> children,
@@ -48,7 +53,8 @@ public class CommitEditor extends JNIObj
                              long replacesRevision)
             throws ClientException
     {
-        notimplemented("addDirectory");
+        nativeAddDirectory(session, relativePath, children, properties,
+                           replacesRevision);
     }
 
     public void addFile(String relativePath,
@@ -58,7 +64,9 @@ public class CommitEditor extends JNIObj
                         long replacesRevision)
             throws ClientException
     {
-        notimplemented("addFile");
+        nativeAddFile(session, relativePath,
+                      checksum, contents, properties,
+                      replacesRevision);
     }
 
     public void addSymlink(String relativePath,
@@ -67,7 +75,8 @@ public class CommitEditor extends JNIObj
                            long replacesRevision)
             throws ClientException
     {
-        notimplemented("addSymlink");
+        nativeAddSymlink(session, relativePath, target, properties,
+                         replacesRevision);
     }
 
     public void addAbsent(String relativePath,
@@ -75,7 +84,7 @@ public class CommitEditor extends JNIObj
                           long replacesRevision)
             throws ClientException
     {
-        notimplemented("addAbsent");
+        nativeAddAbsent(session, relativePath, kind, replacesRevision);
     }
 
     public void alterDirectory(String relativePath,
@@ -84,7 +93,8 @@ public class CommitEditor extends JNIObj
                                Map<String, byte[]> properties)
             throws ClientException
     {
-        notimplemented("alterDirectory");
+        nativeAlterDirectory(session, relativePath, revision,
+                             children, properties);
     }
 
     public void alterFile(String relativePath,
@@ -94,7 +104,8 @@ public class CommitEditor extends JNIObj
                           Map<String, byte[]> properties)
             throws ClientException
     {
-        notimplemented("alterFile");
+        nativeAlterFile(session, relativePath, revision,
+                        checksum, contents, properties);
     }
 
     public void alterSymlink(String relativePath,
@@ -103,14 +114,15 @@ public class CommitEditor extends JNIObj
                              Map<String, byte[]> properties)
             throws ClientException
     {
-        notimplemented("alterSymlink");
+        nativeAlterSymlink(session, relativePath, revision,
+                           target, properties);
     }
 
     public void delete(String relativePath,
                        long revision)
             throws ClientException
     {
-        notimplemented("delete");
+        nativeDelete(session, relativePath, revision);
     }
 
     public void copy(String sourceRelativePath,
@@ -119,7 +131,8 @@ public class CommitEditor extends JNIObj
                      long replacesRevision)
             throws ClientException
     {
-        notimplemented("copy");
+        nativeCopy(session, sourceRelativePath, sourceRevision,
+                   destinationRelativePath, replacesRevision);
     }
 
     public void move(String sourceRelativePath,
@@ -128,44 +141,132 @@ public class CommitEditor extends JNIObj
                      long replacesRevision)
             throws ClientException
     {
-        notimplemented("move");
+        nativeMove(session, sourceRelativePath, sourceRevision,
+                   destinationRelativePath, replacesRevision);
     }
 
     public void rotate(List<RotatePair> elements) throws ClientException
     {
-        notimplemented("rotate");
+        nativeRotate(session, elements);
     }
 
     public void complete() throws ClientException
     {
-        notimplemented("complete");
+        nativeComplete(session);
     }
 
     public void abort() throws ClientException
     {
-        notimplemented("abort");
+        nativeAbort(session);
     }
 
     /**
      * This factory method called from RemoteSession.getCommitEditor.
      */
-    static final CommitEditor createInstance(RemoteSession owner)
+    static final
+        CommitEditor createInstance(RemoteSession session,
+                                    Map<String, byte[]> revisionProperties,
+                                    CommitCallback commitCallback,
+                                    Set<Lock> lockTokens,
+                                    boolean keepLocks)
             throws ClientException
     {
-        // FIXME: temporary implementation
-        return new CommitEditor(0L);
+        long cppAddr = nativeCreateInstance(session,
+                                            revisionProperties, commitCallback,
+                                            lockTokens, keepLocks);
+        return new CommitEditor(cppAddr, session);
     }
 
     /**
-     * This constructor is called from JNI to get an instance.
+     * This constructor is called from the factory to get an instance.
      */
-    protected CommitEditor(long cppAddr)
+    protected CommitEditor(long cppAddr, RemoteSession session)
     {
         super(cppAddr);
+        this.session = session;
     }
 
-    private void notimplemented(String name)
-    {
-        throw new RuntimeException("Not implemented: " + name);
-    }
+    /** Stores a reference to the session that created this editor. */
+    protected RemoteSession session;
+
+    @Override
+    public native void finalize() throws Throwable;
+
+    /*
+     * Wrapped private native implementation declarations.
+     */
+    private native void nativeDispose();
+    private native void nativeAddDirectory(RemoteSession session,
+                                           String relativePath,
+                                           Iterable<String> children,
+                                           Map<String, byte[]> properties,
+                                           long replacesRevision)
+            throws ClientException;
+    private native void nativeAddFile(RemoteSession session,
+                                      String relativePath,
+                                      Checksum checksum,
+                                      InputStream contents,
+                                      Map<String, byte[]> properties,
+                                      long replacesRevision)
+            throws ClientException;
+    private native void nativeAddSymlink(RemoteSession session,
+                                         String relativePath,
+                                         String target,
+                                         Map<String, byte[]> properties,
+                                         long replacesRevision)
+            throws ClientException;
+    private native void nativeAddAbsent(RemoteSession session,
+                                        String relativePath,
+                                        NodeKind kind,
+                                        long replacesRevision)
+            throws ClientException;
+    private native void nativeAlterDirectory(RemoteSession session,
+                                             String relativePath,
+                                             long revision,
+                                             Iterable<String> children,
+                                             Map<String, byte[]> properties)
+            throws ClientException;
+    private native void nativeAlterFile(RemoteSession session,
+                                        String relativePath,
+                                        long revision,
+                                        Checksum checksum,
+                                        InputStream contents,
+                                        Map<String, byte[]> properties)
+            throws ClientException;
+    private native void nativeAlterSymlink(RemoteSession session,
+                                           String relativePath,
+                                           long revision,
+                                           String target,
+                                           Map<String, byte[]> properties)
+            throws ClientException;
+    private native void nativeDelete(RemoteSession session,
+                                     String relativePath,
+                                     long revision)
+            throws ClientException;
+    private native void nativeCopy(RemoteSession session,
+                                   String sourceRelativePath,
+                                   long sourceRevision,
+                                   String destinationRelativePath,
+                                   long replacesRevision)
+            throws ClientException;
+    private native void nativeMove(RemoteSession session,
+                                   String sourceRelativePath,
+                                   long sourceRevision,
+                                   String destinationRelativePath,
+                                   long replacesRevision)
+            throws ClientException;
+    private native void nativeRotate(RemoteSession session,
+                                     List<RotatePair> elements)
+            throws ClientException;
+    private native void nativeComplete(RemoteSession session)
+            throws ClientException;
+    private native void nativeAbort(RemoteSession session)
+            throws ClientException;
+    private static final native
+        long nativeCreateInstance(RemoteSession session,
+                                  Map<String, byte[]> revisionProperties,
+                                  CommitCallback commitCallback,
+                                  Set<Lock> lockTokens,
+                                  boolean keepLocks)
+            throws ClientException;
 }

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java Tue Jun 25 16:43:36 2013
@@ -34,9 +34,9 @@ import org.apache.subversion.javahl.Oper
 import org.apache.subversion.javahl.ClientException;
 
 import java.lang.ref.WeakReference;
-import java.util.HashSet;
 import java.util.Date;
 import java.util.Map;
+import java.util.Set;
 import java.io.OutputStream;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -46,17 +46,16 @@ public class RemoteSession extends JNIOb
 {
     public void dispose()
     {
-        if (editors != null)
+        if (editorReference != null)
         {
-            // Deactivate all open editors
-            for (WeakReference<ISVNEditor> ref : editors)
+            // Deactivate the open editor
+            ISVNEditor ed = editorReference.get();
+            if (ed != null)
             {
-                ISVNEditor ed = ref.get();
-                if (ed == null)
-                    continue;
                 ed.dispose();
-                ref.clear();
+                editorReference.clear();
             }
+            editorReference = null;
         }
         nativeDispose();
     }
@@ -109,12 +108,22 @@ public class RemoteSession extends JNIOb
     public native byte[] getRevisionProperty(long revision, String propertyName)
             throws ClientException;
 
-    public ISVNEditor getCommitEditor() throws ClientException
+    public ISVNEditor getCommitEditor(Map<String, byte[]> revisionProperties,
+                                      CommitCallback commitCallback,
+                                      Set<Lock> lockTokens,
+                                      boolean keepLocks)
+            throws ClientException
     {
-        ISVNEditor ed = CommitEditor.createInstance(this);
-        if (editors == null)
-            editors = new HashSet<WeakReference<ISVNEditor>>();
-        editors.add(new WeakReference<ISVNEditor>(ed));
+        if (editorReference != null && editorReference.get() != null)
+            throw new IllegalStateException("An editor is already active");
+
+        ISVNEditor ed =
+            CommitEditor.createInstance(this, revisionProperties,
+                                        commitCallback, lockTokens, keepLocks);
+
+        if (editorReference != null)
+            editorReference.clear();
+        editorReference = new WeakReference<ISVNEditor>(ed);
         return ed;
     }
 
@@ -143,15 +152,15 @@ public class RemoteSession extends JNIOb
     }
 
     // TODO: getMergeinfo
-    // TODO: doUpdate
-    // TODO: doSwitch
+    // TODO: update
+    // TODO: switch
 
-    public native ISVNReporter doStatus(String statusTarget,
-                                        long revision, Depth depth,
-                                        ISVNEditor statusEditor)
+    public native ISVNReporter status(String statusTarget,
+                                      long revision, Depth depth,
+                                      ISVNEditor statusEditor)
             throws ClientException;
 
-    // TODO: doDiff
+    // TODO: diff
     // TODO: getLog
 
     public native NodeKind checkPath(String path, long revision)
@@ -219,10 +228,28 @@ public class RemoteSession extends JNIOb
     private class RemoteSessionContext extends OperationContext {}
 
     /*
-     * The set of open editors. We need this in order to dispose/abort
-     * the editors when the session is disposed.
+     * A reference to the current open editor. We need this in order
+     * to dispose/abort the editor when the session is disposed. And
+     * furthermore, there can be only one editor active at any time.
      */
-    private HashSet<WeakReference<ISVNEditor>> editors;
+    private WeakReference<ISVNEditor> editorReference;
+
+    /*
+     * The commit editor callse this when disposed to clear the
+     * reference. Note that this function will be called during our
+     * dispose, so make sure they don't step on each others' toes.
+     */
+    void disposeEditor(CommitEditor editor)
+    {
+        if (editorReference == null)
+            return;
+        ISVNEditor ed = editorReference.get();
+        if (ed == null)
+            return;
+        if (ed != editor)
+            throw new IllegalStateException("Disposing unknown editor");
+        editorReference.clear();
+    }
 
     /*
      * Private helper methods.

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1496533&r1=1496532&r2=1496533&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java Tue Jun 25 16:43:36 2013
@@ -237,13 +237,13 @@ public class SVNRemoteTests extends SVNT
     public void testGetCommitEditor() throws Exception
     {
         ISVNRemote session = getSession();
-        session.getCommitEditor();
+        session.getCommitEditor(null, null, null, false);
     }
 
     public void testDisposeCommitEditor() throws Exception
     {
         ISVNRemote session = getSession();
-        session.getCommitEditor();
+        session.getCommitEditor(null, null, null, false);
         session.dispose();
     }
 
@@ -300,10 +300,8 @@ public class SVNRemoteTests extends SVNT
         }
         catch (ClientException ex)
         {
-            String msg = ex.getMessage();
-            int index = msg.indexOf('\n');
             assertEquals("Disabled repository feature",
-                         msg.substring(0, index));
+                         ex.getAllMessages().get(0).getMessage());
             return;
         }