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/27 14:33:22 UTC
svn commit: r1497326 - in /subversion/branches/javahl-1.8-extensions: ./
subversion/bindings/javahl/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/org/apache/subversion/javahl/
subversion/bindings/javahl/src/org/apache/subversion/ja...
Author: brane
Date: Thu Jun 27 12:33:21 2013
New Revision: 1497326
URL: http://svn.apache.org/r1497326
Log:
On the javahl-1.8-extensions branch: Sync JavaHL with trunk up to r1497316.
Added:
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.cpp
- copied, changed from r1497316, subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.h
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Iterator.cpp
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/Iterator.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Iterator.h
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/Iterator.h
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LockTokenTable.cpp
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/LockTokenTable.h
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/LockTokenTable.h
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp
- copied unchanged from r1497316, subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_CommitEditor.cpp
Modified:
subversion/branches/javahl-1.8-extensions/build.conf
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/ (props changed)
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.h
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/JNIUtil.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.h
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/OperationContext.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.cpp
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.h
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/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/ClientException.java
subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNEditor.java
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/remote/CommitEditor.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/tests/org/apache/subversion/javahl/SVNRemoteTests.java
Modified: subversion/branches/javahl-1.8-extensions/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/build.conf?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/build.conf (original)
+++ subversion/branches/javahl-1.8-extensions/build.conf Thu Jun 27 12:33:21 2013
@@ -66,7 +66,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 =
subversion/tests/cmdline/*_tests.py
Propchange: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/
------------------------------------------------------------------------------
Merged /subversion/trunk/subversion/bindings/javahl:r1496335-1497316
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.cpp?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.cpp Thu Jun 27 12:33:21 2013
@@ -37,9 +37,8 @@
* @param jcallback the Java callback object.
*/
CommitCallback::CommitCallback(jobject jcallback)
-{
- m_callback = jcallback;
-}
+ : m_callback(jcallback)
+{}
/**
* Destroy a CommitCallback object
@@ -102,3 +101,14 @@ CommitCallback::commitInfo(const svn_com
env->PopLocalFrame(NULL);
return SVN_NO_ERROR;
}
+
+
+PersistentCommitCallback::PersistentCommitCallback(jobject jcallback)
+ : CommitCallback(JNIUtil::getEnv()->NewGlobalRef(jcallback))
+{}
+
+PersistentCommitCallback::~PersistentCommitCallback()
+{
+ if (m_callback)
+ JNIUtil::getEnv()->DeleteGlobalRef(m_callback);
+}
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.h?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitCallback.h Thu Jun 27 12:33:21 2013
@@ -47,11 +47,26 @@ class CommitCallback
svn_error_t *commitInfo(const svn_commit_info_t *commit_info,
apr_pool_t *pool);
- private:
/**
* This a local reference to the Java object.
*/
jobject m_callback;
};
+/**
+ * Like CommitCallback, but maintains a reference to the Java object
+ * across JNI calls.
+ */
+class PersistentCommitCallback : protected CommitCallback
+{
+ public:
+ PersistentCommitCallback(jobject jcallback);
+ ~PersistentCommitCallback();
+ static svn_error_t *callback(const svn_commit_info_t *commit_info,
+ void *baton, apr_pool_t *pool)
+ {
+ return CommitCallback::callback(commit_info, baton, pool);
+ }
+};
+
#endif // COMMITCALLBACK_H
Copied: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.cpp (from r1497316, subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp)
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.cpp?p2=subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.cpp&p1=subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp&r1=1497316&r2=1497326&rev=1497326&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/CommitEditor.cpp Thu Jun 27 12:33:21 2013
@@ -427,9 +427,9 @@ void CommitEditor::alterFile(jstring jre
return;
SVN_JNI_ERR(svn_editor_alter_file(
m_editor, relpath.c_str(), svn_revnum_t(jrevision),
+ properties.hash(subPool, true),
(jcontents ? &checksum : NULL),
- (jcontents ? contents.getStream(subPool) : NULL),
- properties.hash(subPool, true)),);
+ (jcontents ? contents.getStream(subPool) : NULL)),);
}
void CommitEditor::alterSymlink(jstring jrelpath, jlong jrevision,
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 2013
@@ -191,6 +191,18 @@ int EnumMapper::toLogLevel(jobject jLogL
return getOrdinal(JAVA_PACKAGE"/SVNClient$ClientLogLevel", jLogLevel);
}
+svn_node_kind_t EnumMapper::toNodeKind(jobject jNodeKind)
+{
+ return svn_node_kind_t(
+ getOrdinal(JAVA_PACKAGE"/types/NodeKind", jNodeKind));
+}
+
+svn_checksum_kind_t EnumMapper::toChecksumKind(jobject jChecksumKind)
+{
+ return svn_checksum_kind_t(
+ getOrdinal(JAVA_PACKAGE"/types/Checksum$Kind", jChecksumKind));
+}
+
svn_depth_t EnumMapper::toDepth(jobject jdepth)
{
// The offset for depths is -2
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 2013
@@ -48,6 +48,8 @@ class EnumMapper
static svn_wc_conflict_choice_t toConflictChoice(jobject jchoice);
static int toMergeinfoLogKind(jobject jLogKind);
static int toLogLevel(jobject jLogLevel);
+ static svn_node_kind_t toNodeKind(jobject jNodeKind);
+ static svn_checksum_kind_t toChecksumKind(jobject jChecksumKind);
/* Converting from C enum's */
static jint mapCommitMessageStateFlags(apr_byte_t flags);
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.cpp?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.cpp Thu Jun 27 12:33:21 2013
@@ -418,10 +418,66 @@ JNIUtil::putErrorsInTrace(svn_error_t *e
env->DeleteLocalRef(jfileName);
}
+namespace {
+jobject construct_Jmessage_stack(
+ const JNIUtil::error_message_stack_t& message_stack)
+{
+ JNIEnv *env = JNIUtil::getEnv();
+ env->PushLocalFrame(LOCAL_FRAME_SIZE);
+ if (JNIUtil::isJavaExceptionThrown())
+ return NULL;
+
+ jclass list_clazz = env->FindClass("java/util/ArrayList");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jmethodID mid = env->GetMethodID(list_clazz, "<init>", "(I)V");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jmethodID add_mid = env->GetMethodID(list_clazz, "add",
+ "(Ljava/lang/Object;)Z");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jobject jlist = env->NewObject(list_clazz, mid, jint(message_stack.size()));
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ jclass clazz = env->FindClass(JAVA_PACKAGE"/ClientException$ErrorMessage");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ mid = env->GetMethodID(clazz, "<init>",
+ "(ILjava/lang/String;Z)V");
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ for (JNIUtil::error_message_stack_t::const_iterator
+ it = message_stack.begin();
+ it != message_stack.end(); ++it)
+ {
+ jobject jmessage = JNIUtil::makeJString(it->m_message.c_str());
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ jobject jitem = env->NewObject(clazz, mid,
+ jint(it->m_code), jmessage,
+ jboolean(it->m_generic));
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+ env->CallBooleanMethod(jlist, add_mid, jitem);
+ if (JNIUtil::isJavaExceptionThrown())
+ POP_AND_RETURN_NULL;
+
+ env->DeleteLocalRef(jmessage);
+ env->DeleteLocalRef(jitem);
+ }
+ return env->PopLocalFrame(jlist);
+}
+} // anonymous namespace
+
void JNIUtil::handleSVNError(svn_error_t *err)
{
std::string msg;
- assembleErrorMessage(svn_error_purge_tracing(err), 0, APR_SUCCESS, msg);
+ error_message_stack_t message_stack;
+ assembleErrorMessage(svn_error_purge_tracing(err),
+ 0, APR_SUCCESS, msg, &message_stack);
const char *source = NULL;
#ifdef SVN_DEBUG
#ifndef SVN_ERR__TRACING
@@ -472,12 +528,18 @@ void JNIUtil::handleSVNError(svn_error_t
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
+ jobject jmessageStack = construct_Jmessage_stack(message_stack);
+ if (isJavaExceptionThrown())
+ POP_AND_RETURN_NOTHING();
+
jmethodID mid = env->GetMethodID(clazz, "<init>",
- "(Ljava/lang/String;Ljava/lang/String;I)V");
+ "(Ljava/lang/String;"
+ "Ljava/lang/String;I"
+ "Ljava/util/List;)V");
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
jobject nativeException = env->NewObject(clazz, mid, jmessage, jsource,
- static_cast<jint>(err->apr_err));
+ jint(err->apr_err), jmessageStack);
if (isJavaExceptionThrown())
POP_AND_RETURN_NOTHING();
@@ -875,13 +937,15 @@ jbyteArray JNIUtil::makeJByteArray(const
* @param parent_apr_err the apr of the previous level, used for formating
* @param buffer the buffer where the formated error message will
* be stored
+ * @param message_stack an array of error codes and messages
*/
void JNIUtil::assembleErrorMessage(svn_error_t *err, int depth,
apr_status_t parent_apr_err,
- std::string &buffer)
+ std::string &buffer,
+ error_message_stack_t* message_stack)
{
// buffer for a single error message
- char errbuf[256];
+ char errbuf[1024];
/* Pretty-print the error */
/* Note: we can also log errors here someday. */
@@ -890,35 +954,43 @@ void JNIUtil::assembleErrorMessage(svn_e
* the same as before. */
if (depth == 0 || err->apr_err != parent_apr_err)
{
+ const char *message;
/* Is this a Subversion-specific error code? */
if ((err->apr_err > APR_OS_START_USEERR)
&& (err->apr_err <= APR_OS_START_CANONERR))
- buffer.append(svn_strerror(err->apr_err, errbuf, sizeof(errbuf)));
+ message = svn_strerror(err->apr_err, errbuf, sizeof(errbuf));
/* Otherwise, this must be an APR error code. */
else
{
/* Messages coming from apr_strerror are in the native
encoding, it's a good idea to convert them to UTF-8. */
- const char* utf8_message;
apr_strerror(err->apr_err, errbuf, sizeof(errbuf));
- svn_error_t* utf8_err = svn_utf_cstring_to_utf8(
- &utf8_message, errbuf, err->pool);
+ svn_error_t* utf8_err =
+ svn_utf_cstring_to_utf8(&message, errbuf, err->pool);
if (utf8_err)
{
/* Use fuzzy transliteration instead. */
svn_error_clear(utf8_err);
- utf8_message = svn_utf_cstring_from_utf8_fuzzy(errbuf, err->pool);
+ message = svn_utf_cstring_from_utf8_fuzzy(errbuf, err->pool);
}
- buffer.append(utf8_message);
}
+
+ if (message_stack)
+ message_stack->push_back(
+ message_stack_item(err->apr_err, message, true));
+ buffer.append(message);
buffer.append("\n");
}
if (err->message)
- buffer.append(_("svn: ")).append(err->message).append("\n");
+ {
+ if (message_stack)
+ message_stack->push_back(
+ message_stack_item(err->apr_err, err->message));
+ buffer.append(_("svn: ")).append(err->message).append("\n");
+ }
if (err->child)
assembleErrorMessage(err->child, depth + 1, err->apr_err, buffer);
-
}
/**
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.h?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/JNIUtil.h Thu Jun 27 12:33:21 2013
@@ -37,6 +37,7 @@ class SVNBase;
#include <fstream>
#include <apr_time.h>
#include <string>
+#include <vector>
struct svn_error_t;
#define JAVA_PACKAGE "org/apache/subversion/javahl"
@@ -141,10 +142,26 @@ class JNIUtil
enum { formatBufferSize = 2048 };
enum { noLog, errorLog, exceptionLog, entryLog } LogLevel;
+ struct message_stack_item
+ {
+ apr_status_t m_code;
+ std::string m_message;
+ bool m_generic;
+
+ message_stack_item(apr_status_t code, const char* message,
+ bool generic = false)
+ : m_code(code),
+ m_message(message),
+ m_generic(generic)
+ {}
+ };
+ typedef std::vector<message_stack_item> error_message_stack_t;
+
private:
static void assembleErrorMessage(svn_error_t *err, int depth,
apr_status_t parent_apr_err,
- std::string &buffer);
+ std::string &buffer,
+ error_message_stack_t* message_stack = NULL);
static void putErrorsInTrace(svn_error_t *err,
std::vector<jobject> &stackTrace);
/**
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/OperationContext.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/OperationContext.cpp?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/OperationContext.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/OperationContext.cpp Thu Jun 27 12:33:21 2013
@@ -215,10 +215,7 @@ OperationContext::getAuthBaton(SVN::Pool
jobject OperationContext::getSelf() const
{
- jobject jctx = JNIUtil::getEnv()->NewGlobalRef(m_jctx);
- if (JNIUtil::isJavaExceptionThrown())
- return NULL;
- return jctx;
+ return m_jctx;
}
void
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.cpp?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.cpp (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.cpp Thu Jun 27 12:33:21 2013
@@ -27,18 +27,24 @@
#include <jni.h>
#include "Path.h"
#include "svn_path.h"
+#include "svn_dirent_uri.h"
#include "JNIUtil.h"
+#include "JNIStringHolder.h"
#include "Pool.h"
+#include "svn_private_config.h"
/**
* Constructor
*
- * @see Path::Path(const std::string &)
+ * @see PathBase::PathBase(const std::string &)
* @param path Path string
*/
-Path::Path(const char *pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(const char *pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool)
+ : m_error_occurred(NULL)
{
- init(pi_path, in_pool);
+ init(pi_path, initfunc, in_pool);
}
/**
@@ -48,19 +54,26 @@ Path::Path(const char *pi_path, SVN::Poo
*
* @param path Path string
*/
-Path::Path(const std::string &pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(const std::string &pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool)
+ : m_error_occurred(NULL)
{
- init(pi_path.c_str(), in_pool);
+ init(pi_path.c_str(), initfunc, in_pool);
}
/**
- * Copy constructor
- *
- * @param path Path to be copied
+ * Constructor from a Java string.
*/
-Path::Path(const Path &pi_path, SVN::Pool &in_pool)
+PathBase::PathBase(jstring jpath,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool)
+ : m_error_occurred(NULL)
{
- init(pi_path.c_str(), in_pool);
+ JNIStringHolder path(jpath);
+ if (JNIUtil::isJavaExceptionThrown())
+ return;
+ init(path, initfunc, in_pool);
}
/**
@@ -69,17 +82,13 @@ Path::Path(const Path &pi_path, SVN::Poo
* @param path Path string
*/
void
-Path::init(const char *pi_path, SVN::Pool &in_pool)
+PathBase::init(const char *pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool)
{
- if (*pi_path == 0)
- {
- m_error_occurred = NULL;
- m_path = "";
- }
- else
+ if (pi_path && *pi_path)
{
- m_error_occurred = JNIUtil::preprocessPath(pi_path, in_pool.getPool());
-
+ m_error_occurred = initfunc(pi_path, in_pool);
m_path = pi_path;
}
}
@@ -88,7 +97,7 @@ Path::init(const char *pi_path, SVN::Poo
* @return Path string
*/
const std::string &
-Path::path() const
+PathBase::path() const
{
return m_path;
}
@@ -97,7 +106,7 @@ Path::path() const
* @return Path string as a C string
*/
const char *
-Path::c_str() const
+PathBase::c_str() const
{
return m_path.c_str();
}
@@ -105,8 +114,8 @@ Path::c_str() const
/**
* Assignment operator
*/
-Path&
-Path::operator=(const Path &pi_path)
+PathBase&
+PathBase::operator=(const PathBase &pi_path)
{
m_error_occurred = NULL;
m_path = pi_path.m_path;
@@ -114,12 +123,12 @@ Path::operator=(const Path &pi_path)
return *this;
}
- svn_error_t *Path::error_occurred() const
+svn_error_t *PathBase::error_occurred() const
{
return m_error_occurred;
}
-jboolean Path::isValid(const char *p)
+jboolean PathBase::isValid(const char *p)
{
if (p == NULL)
return JNI_FALSE;
@@ -136,3 +145,25 @@ jboolean Path::isValid(const char *p)
return JNI_FALSE;
}
}
+
+svn_error_t*
+Path::initfunc(const char*& path, SVN::Pool& pool)
+{
+ return JNIUtil::preprocessPath(path, pool.getPool());
+}
+
+svn_error_t*
+URL::initfunc(const char*& path, SVN::Pool& pool)
+{
+ if (svn_path_is_url(path))
+ return JNIUtil::preprocessPath(path, pool.getPool());
+ return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+ _("Not an URL: %s"), path);
+}
+
+svn_error_t*
+Relpath::initfunc(const char*& path, SVN::Pool& pool)
+{
+ path = svn_relpath__internal_style(path, pool.getPool());
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.h?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.h (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/native/Path.h Thu Jun 27 12:33:21 2013
@@ -24,18 +24,19 @@
* @brief Interface of the C++ class Path.
*/
-#ifndef PATH_H
-#define PATH_H
+#ifndef JAVAHL_PATH_H
+#define JAVAHL_PATH_H
#include <string>
#include <jni.h>
#include "Pool.h"
struct svn_error_t;
+
/**
* Encapsulation for Subversion Path handling
*/
-class Path
+class PathBase
{
private:
// The path to be stored.
@@ -48,9 +49,11 @@ class Path
*
* @param pi_path Path string
*/
- void init(const char *pi_path, SVN::Pool &in_pool);
+ void init(const char *pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool);
- public:
+ protected:
/**
* Constructor that takes a string as parameter.
* The string is converted to subversion internal
@@ -58,27 +61,31 @@ class Path
*
* @param pi_path Path string
*/
- Path(const std::string &pi_path, SVN::Pool &in_pool);
+ PathBase(const std::string &pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool);
/**
* Constructor
*
- * @see Path::Path (const std::string &)
+ * @see PathBase::PathBase (const std::string &)
* @param pi_path Path string
*/
- Path(const char *pi_path, SVN::Pool &in_pool);
+ PathBase(const char *pi_path,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool);
/**
- * Copy constructor
- *
- * @param pi_path Path to be copied
+ * Constructor from a Java string.
*/
- Path(const Path &pi_path, SVN::Pool &in_pool);
+ PathBase(jstring jpath,
+ svn_error_t* initfunc(const char*&, SVN::Pool&),
+ SVN::Pool &in_pool);
/**
* Assignment operator
*/
- Path &operator=(const Path&);
+ PathBase &operator=(const PathBase&);
/**
* @return Path string
@@ -92,6 +99,7 @@ class Path
svn_error_t *error_occurred() const;
+public:
/**
* Returns whether @a path is non-NULL and passes the @c
* svn_path_check_valid() test.
@@ -101,4 +109,113 @@ class Path
static jboolean isValid(const char *path);
};
-#endif // PATH_H
+
+/**
+ * Dirent or URI
+ */
+class Path : protected PathBase
+{
+ public:
+ Path(const std::string &pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ Path(const char *pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ Path(jstring jpath, SVN::Pool &in_pool)
+ : PathBase(jpath, initfunc, in_pool)
+ {}
+
+ Path& operator=(const Path& that)
+ {
+ PathBase::operator=(that);
+ return *this;
+ }
+
+ const std::string &path() const { return PathBase::path(); }
+ const char *c_str() const { return PathBase::c_str(); }
+
+ svn_error_t *error_occurred() const
+ {
+ return PathBase::error_occurred();
+ }
+
+ private:
+ static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+/**
+ * URL
+ */
+class URL : protected PathBase
+{
+ public:
+ URL(const std::string &pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ URL(const char *pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ URL(jstring jpath, SVN::Pool &in_pool)
+ : PathBase(jpath, initfunc, in_pool)
+ {}
+
+ URL& operator=(const URL& that)
+ {
+ PathBase::operator=(that);
+ return *this;
+ }
+
+ const std::string &path() const { return PathBase::path(); }
+ const char *c_str() const { return PathBase::c_str(); }
+
+ svn_error_t *error_occurred() const
+ {
+ return PathBase::error_occurred();
+ }
+
+ private:
+ static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+/**
+ * Relative path
+ */
+class Relpath : protected PathBase
+{
+ public:
+ Relpath(const std::string &pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ Relpath(const char *pi_path, SVN::Pool &in_pool)
+ : PathBase(pi_path, initfunc, in_pool)
+ {}
+
+ Relpath(jstring jpath, SVN::Pool &in_pool)
+ : PathBase(jpath, initfunc, in_pool)
+ {}
+
+ Relpath& operator=(const Relpath& that)
+ {
+ PathBase::operator=(that);
+ return *this;
+ }
+
+ const std::string &path() const { return PathBase::path(); }
+ const char *c_str() const { return PathBase::c_str(); }
+
+ svn_error_t *error_occurred() const
+ {
+ return PathBase::error_occurred();
+ }
+
+ private:
+ static svn_error_t* initfunc(const char*&, SVN::Pool&);
+};
+
+#endif // JAVAHL_PATH_H
Modified: subversion/branches/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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 2013
@@ -30,6 +30,7 @@
#include "JNIByteArray.h"
#include "JNIStringHolder.h"
#include "JNIUtil.h"
+#include "Path.h"
#include "svn_ra.h"
#include "svn_string.h"
@@ -64,9 +65,11 @@ RemoteSession::open(jint jretryAttempts,
{
JNIEnv *env = JNIUtil::getEnv();
- JNIStringHolder url(jurl);
+ SVN::Pool requestPool;
+ URL url(jurl, requestPool);
if (JNIUtil::isExceptionThrown())
return NULL;
+ SVN_JNI_ERR(url.error_occurred(), NULL);
env->DeleteLocalRef(jurl);
JNIStringHolder uuid(juuid);
@@ -98,7 +101,7 @@ RemoteSession::open(jint jretryAttempts,
}
jobject jremoteSession = open(
- jretryAttempts, url, uuid, configDirectory,
+ jretryAttempts, url.c_str(), uuid, configDirectory,
usernameStr, passwordStr, prompter, jprogress);
if (JNIUtil::isExceptionThrown() || !jremoteSession)
{
@@ -279,12 +282,13 @@ RemoteSession::dispose(jobject jthis)
void RemoteSession::reparent(jstring jurl)
{
- JNIStringHolder url(jurl);
- if (JNIUtil::isJavaExceptionThrown())
+ SVN::Pool subPool(pool);
+ URL url(jurl, subPool);
+ if (JNIUtil::isExceptionThrown())
return;
+ SVN_JNI_ERR(url.error_occurred(),);
- SVN::Pool subPool(pool);
- SVN_JNI_ERR(svn_ra_reparent(m_session, url, subPool.getPool()), );
+ SVN_JNI_ERR(svn_ra_reparent(m_session, url.c_str(), subPool.getPool()), );
}
jstring
@@ -304,14 +308,15 @@ RemoteSession::getSessionUrl()
jstring
RemoteSession::getSessionRelativePath(jstring jurl)
{
- JNIStringHolder url(jurl);
- if (JNIUtil::isJavaExceptionThrown())
+ SVN::Pool subPool(pool);
+ URL url(jurl, subPool);
+ if (JNIUtil::isExceptionThrown())
return NULL;
+ SVN_JNI_ERR(url.error_occurred(), NULL);
- SVN::Pool subPool(pool);
const char* rel_path;
SVN_JNI_ERR(svn_ra_get_path_relative_to_session(
- m_session, &rel_path, url, subPool.getPool()),
+ m_session, &rel_path, url.c_str(), subPool.getPool()),
NULL);
jstring jrel_path = JNIUtil::makeJString(rel_path);
if (JNIUtil::isJavaExceptionThrown())
@@ -323,13 +328,15 @@ RemoteSession::getSessionRelativePath(js
jstring
RemoteSession::getReposRelativePath(jstring jurl)
{
- JNIStringHolder url(jurl);
- if (JNIUtil::isJavaExceptionThrown())
+ SVN::Pool subPool(pool);
+ URL url(jurl, subPool);
+ if (JNIUtil::isExceptionThrown())
return NULL;
+ SVN_JNI_ERR(url.error_occurred(), NULL);
- SVN::Pool subPool(pool);
const char* rel_path;
- SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &rel_path, url,
+ SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &rel_path,
+ url.c_str(),
subPool.getPool()),
NULL);
@@ -470,21 +477,22 @@ jlong
RemoteSession::getFile(jlong jrevision, jstring jpath,
jobject jcontents, jobject jproperties)
{
- JNIStringHolder path(jpath);
+ OutputStream contents_proxy(jcontents);
if (JNIUtil::isExceptionThrown())
return SVN_INVALID_REVNUM;
- OutputStream contents_proxy(jcontents);
+ SVN::Pool subPool(pool);
+ Relpath path(jpath, subPool);
if (JNIUtil::isExceptionThrown())
return SVN_INVALID_REVNUM;
+ SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
- SVN::Pool subPool(pool);
apr_hash_t* props = NULL;
svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
svn_stream_t* contents = (!jcontents ? NULL
: contents_proxy.getStream(subPool));
- SVN_JNI_ERR(svn_ra_get_file(m_session, path, fetched_rev,
+ SVN_JNI_ERR(svn_ra_get_file(m_session, path.c_str(), fetched_rev,
contents, &fetched_rev,
(jproperties ? &props : NULL),
subPool.getPool()),
@@ -578,18 +586,20 @@ RemoteSession::getDirectory(jlong jrevis
jint jdirent_fields, jobject jdirents,
jobject jproperties)
{
- JNIStringHolder path(jpath);
+ SVN::Pool subPool(pool);
+ Relpath path(jpath, subPool);
if (JNIUtil::isExceptionThrown())
return SVN_INVALID_REVNUM;
+ SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
- SVN::Pool subPool(pool);
apr_hash_t* props = NULL;
apr_hash_t* dirents = NULL;
svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
SVN_JNI_ERR(svn_ra_get_dir2(m_session, (jdirents ? &dirents : NULL),
&fetched_rev, (jproperties ? &props : NULL),
- path, fetched_rev, apr_uint32_t(jdirent_fields),
+ path.c_str(), fetched_rev,
+ apr_uint32_t(jdirent_fields),
subPool.getPool()),
SVN_INVALID_REVNUM);
@@ -601,7 +611,8 @@ RemoteSession::getDirectory(jlong jrevis
SVN_JNI_ERR(svn_ra_get_session_url(m_session, &base_url,
subPool.getPool()),
SVN_INVALID_REVNUM);
- fill_dirents(base_url, path, jdirents, dirents, subPool.getPool());
+ fill_dirents(base_url, path.c_str(), jdirents, dirents,
+ subPool.getPool());
if (JNIUtil::isExceptionThrown())
return SVN_INVALID_REVNUM;
}
@@ -617,30 +628,31 @@ 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
RemoteSession::checkPath(jstring jpath, jlong jrevision)
{
- JNIStringHolder path(jpath);
+ SVN::Pool subPool(pool);
+ Relpath path(jpath, subPool);
if (JNIUtil::isExceptionThrown())
return NULL;
+ SVN_JNI_ERR(path.error_occurred(), NULL);
- SVN::Pool subPool(pool);
svn_node_kind_t kind;
- SVN_JNI_ERR(svn_ra_check_path(m_session, path,
+ SVN_JNI_ERR(svn_ra_check_path(m_session, path.c_str(),
svn_revnum_t(jrevision),
&kind, subPool.getPool()),
NULL);
@@ -659,17 +671,18 @@ RemoteSession::checkPath(jstring jpath,
jobject
RemoteSession::getLocks(jstring jpath, jobject jdepth)
{
- JNIStringHolder path(jpath);
+ svn_depth_t depth = EnumMapper::toDepth(jdepth);
if (JNIUtil::isExceptionThrown())
return NULL;
- svn_depth_t depth = EnumMapper::toDepth(jdepth);
+ SVN::Pool subPool(pool);
+ Relpath path(jpath, subPool);
if (JNIUtil::isExceptionThrown())
return NULL;
+ SVN_JNI_ERR(path.error_occurred(), NULL);
- SVN::Pool subPool(pool);
apr_hash_t *locks;
- SVN_JNI_ERR(svn_ra_get_locks2(m_session, &locks, path, depth,
+ SVN_JNI_ERR(svn_ra_get_locks2(m_session, &locks, path.c_str(), depth,
subPool.getPool()),
NULL);
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 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,
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 2013
@@ -1576,12 +1576,7 @@ SVNClient::openRemoteSession(const char*
by creating a copy of the prompter here. */
Prompter* prompter = new Prompter(context.getPrompter());
if (!prompter)
- {
- /* context.getSelf() created a new global reference. */
- JNIUtil::getEnv()->DeleteGlobalRef(jctx);
- JNIUtil::throwNullPointerException("allocating Prompter");
- return NULL;
- }
+ return NULL;
jobject jremoteSession = RemoteSession::open(
retryAttempts, path_info.url.c_str(), path_info.uuid.c_str(),
@@ -1589,12 +1584,7 @@ SVNClient::openRemoteSession(const char*
context.getUsername(), context.getPassword(),
prompter, jctx);
if (JNIUtil::isJavaExceptionThrown())
- {
- /* context.getSelf() created a new global reference. */
- JNIUtil::getEnv()->DeleteGlobalRef(jctx);
- jremoteSession = NULL;
- delete prompter;
- }
+ delete prompter;
return jremoteSession;
}
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 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/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientException.java Thu Jun 27 12:33:21 2013
@@ -22,6 +22,7 @@
*/
package org.apache.subversion.javahl;
+import java.util.List;
/**
* This exception is thrown whenever something goes wrong in the
@@ -36,7 +37,54 @@ public class ClientException extends Nat
// http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf
// http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/version.html#6678
// http://java.sun.com/javase/6/docs/platform/serialization/spec/version.html#6678
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
+
+ /**
+ * Describes a single error message in a stack of messages
+ * associated with this exception.
+ * @since 1.9
+ */
+ public static final class ErrorMessage
+ {
+ ErrorMessage(int code, String message, boolean generic)
+ {
+ this.code = code;
+ this.message = message;
+ this.generic = generic;
+ }
+
+ /** @return The APR error code associated with the message. */
+ public final int getCode() { return code; }
+
+ /** @return The error message text. */
+ public final String getMessage() { return message; }
+
+ /** @return A flag indicating whether this is a generic
+ message for the APR error code, or a more specific message
+ generated by the native libraries. */
+ public final boolean isGeneric() { return generic; }
+
+ private final int code;
+ private final String message;
+ private final boolean generic;
+ };
+
+ /**
+ * This constructor is only used by the native library.
+ *
+ * @param message A description of the problem.
+ * @param source The error's source.
+ * @param aprError Any associated APR error code for a wrapped
+ * <code>svn_error_t</code>.
+ * @param messageStack The whole stack of error messages
+ * @since 1.9
+ */
+ ClientException(String message, String source, int aprError,
+ List<ErrorMessage> messageStack)
+ {
+ super(message, source, aprError);
+ this.messageStack = messageStack;
+ }
/**
* This constructor is only used by the native library.
@@ -48,7 +96,12 @@ public class ClientException extends Nat
*/
ClientException(String message, String source, int aprError)
{
- super(message, source, aprError);
+ this(message, source, aprError, null);
+ }
+
+ public List<ErrorMessage> getAllMessages()
+ {
+ return messageStack;
}
/**
@@ -68,4 +121,6 @@ public class ClientException extends Nat
return new ClientException(t.getMessage(), null, -1);
}
}
+
+ private final List<ErrorMessage> messageStack;
}
Modified: subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNEditor.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNEditor.java?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNEditor.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNEditor.java Thu Jun 27 12:33:21 2013
@@ -27,7 +27,6 @@ import org.apache.subversion.javahl.type
import org.apache.subversion.javahl.callback.*;
import java.io.InputStream;
-import java.util.List;
import java.util.Map;
/**
@@ -296,7 +295,7 @@ public interface ISVNEditor
*
* @throws ClientException
*/
- void rotate(List<RotatePair> elements) throws ClientException;
+ void rotate(Iterable<RotatePair> elements) throws ClientException;
public static final class RotatePair
{
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 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/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java?rev=1497326&r1=1497325&r2=1497326&view=diff
==============================================================================
--- subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java (original)
+++ subversion/branches/javahl-1.8-extensions/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/CommitEditor.java Thu Jun 27 12:33:21 2013
@@ -31,8 +31,8 @@ import org.apache.subversion.javahl.JNIO
import org.apache.subversion.javahl.ClientException;
import java.io.InputStream;
-import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Implementation of ISVNEditor that drives commits.
@@ -40,132 +40,127 @@ import java.util.Map;
*/
public class CommitEditor extends JNIObject implements ISVNEditor
{
- public void dispose() {/* TODO */}
-
- public void addDirectory(String relativePath,
- Iterable<String> children,
- Map<String, byte[]> properties,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("addDirectory");
- }
-
- public void addFile(String relativePath,
- Checksum checksum,
- InputStream contents,
- Map<String, byte[]> properties,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("addFile");
- }
-
- public void addSymlink(String relativePath,
- String target,
- Map<String, byte[]> properties,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("addSymlink");
- }
-
- public void addAbsent(String relativePath,
- NodeKind kind,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("addAbsent");
- }
-
- public void alterDirectory(String relativePath,
- long revision,
- Iterable<String> children,
- Map<String, byte[]> properties)
- throws ClientException
- {
- notimplemented("alterDirectory");
- }
-
- public void alterFile(String relativePath,
- long revision,
- Checksum checksum,
- InputStream contents,
- Map<String, byte[]> properties)
- throws ClientException
- {
- notimplemented("alterFile");
- }
-
- public void alterSymlink(String relativePath,
- long revision,
- String target,
- Map<String, byte[]> properties)
- throws ClientException
+ public void dispose()
{
- notimplemented("alterSymlink");
+ session.disposeEditor(this);
+ nativeDispose();
}
- public void delete(String relativePath,
- long revision)
- throws ClientException
- {
- notimplemented("delete");
- }
+ public native void addDirectory(String relativePath,
+ Iterable<String> children,
+ Map<String, byte[]> properties,
+ long replacesRevision)
+ throws ClientException;
+
+ public native void addFile(String relativePath,
+ Checksum checksum,
+ InputStream contents,
+ Map<String, byte[]> properties,
+ long replacesRevision)
+ throws ClientException;
- public void copy(String sourceRelativePath,
- long sourceRevision,
- String destinationRelativePath,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("copy");
- }
+ /**
+ * <b>Note:</b> Not implemented.
+ */
+ public native void addSymlink(String relativePath,
+ String target,
+ Map<String, byte[]> properties,
+ long replacesRevision)
+ throws ClientException;
+
+ public native void addAbsent(String relativePath,
+ NodeKind kind,
+ long replacesRevision)
+ throws ClientException;
+
+ public native void alterDirectory(String relativePath,
+ long revision,
+ Iterable<String> children,
+ Map<String, byte[]> properties)
+ throws ClientException;
+
+ public native void alterFile(String relativePath,
+ long revision,
+ Checksum checksum,
+ InputStream contents,
+ Map<String, byte[]> properties)
+ throws ClientException;
- public void move(String sourceRelativePath,
- long sourceRevision,
- String destinationRelativePath,
- long replacesRevision)
- throws ClientException
- {
- notimplemented("move");
- }
+ /**
+ * <b>Note:</b> Not implemented.
+ */
+ public native void alterSymlink(String relativePath,
+ long revision,
+ String target,
+ Map<String, byte[]> properties)
+ throws ClientException;
+
+ public native void delete(String relativePath,
+ long revision)
+ throws ClientException;
+
+ public native void copy(String sourceRelativePath,
+ long sourceRevision,
+ String destinationRelativePath,
+ long replacesRevision)
+ throws ClientException;
+
+ public native void move(String sourceRelativePath,
+ long sourceRevision,
+ String destinationRelativePath,
+ long replacesRevision)
+ throws ClientException;
- public void rotate(List<RotatePair> elements) throws ClientException
- {
- notimplemented("rotate");
- }
+ /**
+ * <b>Note:</b> Not implemented.
+ */
+ public native void rotate(Iterable<RotatePair> elements)
+ throws ClientException;
- public void complete() throws ClientException
- {
- notimplemented("complete");
- }
+ public native void complete() throws ClientException;
- public void abort() throws ClientException
- {
- notimplemented("abort");
- }
+ public native void abort() throws ClientException;
/**
* 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 static final native
+ long nativeCreateInstance(RemoteSession session,
+ Map<String, byte[]> revisionProperties,
+ CommitCallback commitCallback,
+ Set<Lock> lockTokens,
+ boolean keepLocks)
+ throws ClientException;
}
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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 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/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=1497326&r1=1497325&r2=1497326&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 Thu Jun 27 12:33:21 2013
@@ -24,17 +24,22 @@ package org.apache.subversion.javahl;
import org.apache.subversion.javahl.*;
import org.apache.subversion.javahl.remote.*;
+import org.apache.subversion.javahl.callback.*;
import org.apache.subversion.javahl.types.*;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
/**
* This class is used for testing the SVNReposAccess class
@@ -237,13 +242,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 +305,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;
}
@@ -370,4 +373,313 @@ public class SVNRemoteTests extends SVNT
for (Map.Entry<String, byte[]> e : properties.entrySet())
assertTrue(e.getKey().startsWith("svn:entry:"));
}
+
+ private final class CommitContext implements CommitCallback
+ {
+ public final ISVNEditor editor;
+ public CommitContext(ISVNRemote session, String logstr)
+ throws ClientException
+ {
+ Charset UTF8 = Charset.forName("UTF-8");
+ byte[] log = (logstr == null
+ ? new byte[0]
+ : logstr.getBytes(UTF8));
+ HashMap<String, byte[]> revprops = new HashMap<String, byte[]>();
+ revprops.put("svn:log", log);
+ editor = session.getCommitEditor(revprops, this, null, false);
+ }
+
+ public void commitInfo(CommitInfo info) { this.info = info; }
+ public long getRevision() { return info.getRevision(); }
+
+ private CommitInfo info;
+ }
+
+ public void testEditorCopy() throws Exception
+ {
+ ISVNRemote session = getSession();
+ CommitContext cc =
+ new CommitContext(session, "Copy A/B/lambda -> A/B/omega");
+
+ try {
+ // FIXME: alter dir A/B first
+ cc.editor.copy("A/B/lambda", 1, "A/B/omega",
+ Revision.SVN_INVALID_REVNUM);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ assertEquals(NodeKind.file,
+ session.checkPath("A/B/lambda",
+ Revision.SVN_INVALID_REVNUM));
+ assertEquals(NodeKind.file,
+ session.checkPath("A/B/omega",
+ Revision.SVN_INVALID_REVNUM));
+ }
+
+ public void testEditorMove() throws Exception
+ {
+ ISVNRemote session = getSession();
+ CommitContext cc =
+ new CommitContext(session, "Move A/B/lambda -> A/B/omega");
+
+ try {
+ // FIXME: alter dir A/B first
+ cc.editor.move("A/B/lambda", 1, "A/B/omega",
+ Revision.SVN_INVALID_REVNUM);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ assertEquals(NodeKind.none,
+ session.checkPath("A/B/lambda",
+ Revision.SVN_INVALID_REVNUM));
+ assertEquals(NodeKind.file,
+ session.checkPath("A/B/omega",
+ Revision.SVN_INVALID_REVNUM));
+ }
+
+ public void testEditorDelete() throws Exception
+ {
+ ISVNRemote session = getSession();
+ CommitContext cc =
+ new CommitContext(session, "Delete all greek files");
+
+ String[] filePaths = { "iota",
+ "A/mu",
+ "A/B/lambda",
+ "A/B/E/alpha",
+ "A/B/E/beta",
+ "A/D/gamma",
+ "A/D/G/pi",
+ "A/D/G/rho",
+ "A/D/G/tau",
+ "A/D/H/chi",
+ "A/D/H/omega",
+ "A/D/H/psi" };
+
+ try {
+ // FIXME: alter a bunch of dirs first
+ for (String path : filePaths)
+ cc.editor.delete(path, 1);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ for (String path : filePaths)
+ assertEquals(NodeKind.none,
+ session.checkPath(path, Revision.SVN_INVALID_REVNUM));
+ }
+
+ public void testEditorMkdir() throws Exception
+ {
+ ISVNRemote session = getSession();
+ CommitContext cc = new CommitContext(session, "Make hebrew dir");
+
+ try {
+ // FIXME: alter dir . first
+ cc.editor.addDirectory("ALEPH",
+ new ArrayList<String>(),
+ new HashMap<String, byte[]>(),
+ Revision.SVN_INVALID_REVNUM);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ assertEquals(NodeKind.dir,
+ session.checkPath("ALEPH",
+ Revision.SVN_INVALID_REVNUM));
+ }
+
+ public void testEditorSetDirProps() throws Exception
+ {
+ Charset UTF8 = Charset.forName("UTF-8");
+ ISVNRemote session = getSession();
+
+ byte[] ignoreval = "*.pyc\n.gitignore\n".getBytes(UTF8);
+ HashMap<String, byte[]> props = new HashMap<String, byte[]>();
+ props.put("svn:ignore", ignoreval);
+
+ CommitContext cc = new CommitContext(session, "Add svn:ignore");
+ try {
+ cc.editor.alterDirectory("", 1, null, props);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ assertTrue(Arrays.equals(ignoreval,
+ client.propertyGet(session.getSessionUrl(),
+ "svn:ignore",
+ Revision.HEAD,
+ Revision.HEAD)));
+ }
+
+ private static byte[] SHA1(byte[] text) throws NoSuchAlgorithmException
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ return md.digest(text);
+ }
+
+ public void testEditorAddFile() throws Exception
+ {
+ Charset UTF8 = Charset.forName("UTF-8");
+ ISVNRemote session = getSession();
+
+ byte[] eolstyle = "native".getBytes(UTF8);
+ HashMap<String, byte[]> props = new HashMap<String, byte[]>();
+ props.put("svn:eol-style", eolstyle);
+
+ byte[] contents = "This is file 'xi'.".getBytes(UTF8);
+ Checksum hash = new Checksum(SHA1(contents), Checksum.Kind.SHA1);
+ ByteArrayInputStream stream = new ByteArrayInputStream(contents);
+
+ CommitContext cc = new CommitContext(session, "Add A/xi");
+ try {
+ // FIXME: alter dir A first
+ cc.editor.addFile("A/xi", hash, stream, props,
+ Revision.SVN_INVALID_REVNUM);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ assertEquals(NodeKind.file,
+ session.checkPath("A/xi",
+ Revision.SVN_INVALID_REVNUM));
+
+ byte[] propval = client.propertyGet(session.getSessionUrl() + "/A/xi",
+ "svn:eol-style",
+ Revision.HEAD,
+ Revision.HEAD);
+ assertTrue(Arrays.equals(eolstyle, propval));
+ }
+
+ public void testEditorSetFileProps() throws Exception
+ {
+ Charset UTF8 = Charset.forName("UTF-8");
+ ISVNRemote session = getSession();
+
+ byte[] eolstyle = "CRLF".getBytes(UTF8);
+ HashMap<String, byte[]> props = new HashMap<String, byte[]>();
+ props.put("svn:eol-style", eolstyle);
+
+ CommitContext cc =
+ new CommitContext(session, "Change eol-style on A/B/E/alpha");
+ try {
+ cc.editor.alterFile("A/B/E/alpha", 1, null, null, props);
+ cc.editor.complete();
+ } finally {
+ cc.editor.dispose();
+ }
+
+ assertEquals(2, cc.getRevision());
+ assertEquals(2, session.getLatestRevision());
+ byte[] propval = client.propertyGet(session.getSessionUrl()
+ + "/A/B/E/alpha",
+ "svn:eol-style",
+ Revision.HEAD,
+ Revision.HEAD);
+ assertTrue(Arrays.equals(eolstyle, propval));
+ }
+
+ // public void testEditorRotate() throws Exception
+ // {
+ // ISVNRemote session = getSession();
+ //
+ // ArrayList<ISVNEditor.RotatePair> rotation =
+ // new ArrayList<ISVNEditor.RotatePair>(3);
+ // rotation.add(new ISVNEditor.RotatePair("A/B", 1));
+ // rotation.add(new ISVNEditor.RotatePair("A/C", 1));
+ // rotation.add(new ISVNEditor.RotatePair("A/D", 1));
+ //
+ // CommitContext cc =
+ // new CommitContext(session, "Rotate A/B -> A/C -> A/D");
+ // try {
+ // // No alter-dir of A is needed, children remain the same.
+ // cc.editor.rotate(rotation);
+ // cc.editor.complete();
+ // } finally {
+ // cc.editor.dispose();
+ // }
+ //
+ // assertEquals(2, cc.getRevision());
+ // assertEquals(2, session.getLatestRevision());
+ //
+ // HashMap<String, DirEntry> dirents = new HashMap<String, DirEntry>();
+ // HashMap<String, byte[]> properties = new HashMap<String, byte[]>();
+ //
+ // // A/B is now what used to be A/D, so A/B/H must exist
+ // session.getDirectory(Revision.SVN_INVALID_REVNUM, "A/B",
+ // DirEntry.Fields.all, dirents, properties);
+ // assertEquals(dirents.get("H").getPath(), "H");
+ //
+ // // A/C is now what used to be A/B, so A/C/F must exist
+ // session.getDirectory(Revision.SVN_INVALID_REVNUM, "A/C",
+ // DirEntry.Fields.all, dirents, properties);
+ // assertEquals(dirents.get("F").getPath(), "F");
+ //
+ // // A/D is now what used to be A/C and must be empty
+ // session.getDirectory(Revision.SVN_INVALID_REVNUM, "A/D",
+ // DirEntry.Fields.all, dirents, properties);
+ // assertTrue(dirents.isEmpty());
+ // }
+
+ // Sanity check so that we don't forget about unimplemented methods.
+ public void testEditorNotImplemented() throws Exception
+ {
+ ISVNRemote session = getSession();
+
+ HashMap<String, byte[]> props = new HashMap<String, byte[]>();
+ ArrayList<ISVNEditor.RotatePair> rotation =
+ new ArrayList<ISVNEditor.RotatePair>();
+
+ CommitContext cc = new CommitContext(session, "not implemented");
+ try {
+ String exmsg;
+
+ try {
+ exmsg = "";
+ cc.editor.addSymlink("", "", props, 1);
+ } catch (IllegalStateException ex) {
+ exmsg = ex.getMessage();
+ }
+ assertEquals("Not implemented: CommitEditor.addSymlink", exmsg);
+
+ try {
+ exmsg = "";
+ cc.editor.alterSymlink("", 1, "", null);
+ } catch (IllegalStateException ex) {
+ exmsg = ex.getMessage();
+ }
+ assertEquals("Not implemented: CommitEditor.alterSymlink", exmsg);
+
+ try {
+ exmsg = "";
+ cc.editor.rotate(rotation);
+ } catch (IllegalStateException ex) {
+ exmsg = ex.getMessage();
+ }
+ assertEquals("Not implemented: CommitEditor.rotate", exmsg);
+ } finally {
+ cc.editor.dispose();
+ }
+
+ }
}