3
* ====================================================================
4
* Licensed to the Apache Software Foundation (ASF) under one
5
* or more contributor license agreements. See the NOTICE file
6
* distributed with this work for additional information
7
* regarding copyright ownership. The ASF licenses this file
8
* to you under the Apache License, Version 2.0 (the
9
* "License"); you may not use this file except in compliance
10
* with the License. You may obtain a copy of the License at
12
* http://www.apache.org/licenses/LICENSE-2.0
14
* Unless required by applicable law or agreed to in writing,
15
* software distributed under the License is distributed on an
16
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
* KIND, either express or implied. See the License for the
18
* specific language governing permissions and limitations
20
* ====================================================================
23
* @file RemoteSession.cpp
24
* @brief Implementation of the class RemoteSession
31
#include "JNIByteArray.h"
32
#include "JNIStringHolder.h"
37
#include "svn_string.h"
38
#include "svn_dirent_uri.h"
39
#include "svn_delta.h"
42
#include "EnumMapper.h"
44
#include "LogMessageCallback.h"
45
#include "OutputStream.h"
48
#include "RemoteSession.h"
49
#include "EditorProxy.h"
50
#include "StateReporter.h"
52
#include <apr_strings.h>
53
#include "svn_private_config.h"
55
#define JAVA_CLASS_REMOTE_SESSION JAVAHL_CLASS("/remote/RemoteSession")
58
RemoteSession::getCppObject(jobject jthis)
60
static jfieldID fid = 0;
61
jlong cppAddr = SVNBase::findCppAddrForJObject(jthis, &fid,
62
JAVA_CLASS_REMOTE_SESSION);
63
return (cppAddr == 0 ? NULL : reinterpret_cast<RemoteSession *>(cppAddr));
67
RemoteSession::open(jint jretryAttempts,
68
jstring jurl, jstring juuid,
69
jstring jconfigDirectory,
70
jstring jusername, jstring jpassword,
71
jobject jprompter, jobject jdeprecatedPrompter,
72
jobject jprogress, jobject jcfgcb, jobject jtunnelcb)
74
SVN_ERR_ASSERT_NO_RETURN(!(jprompter && jdeprecatedPrompter));
76
SVN::Pool requestPool;
77
URL url(jurl, requestPool);
78
if (JNIUtil::isExceptionThrown())
80
SVN_JNI_ERR(url.error_occurred(), NULL);
82
JNIStringHolder uuid(juuid);
83
if (JNIUtil::isExceptionThrown())
86
Path configDirectory(jconfigDirectory, requestPool);
87
if (JNIUtil::isExceptionThrown())
89
SVN_JNI_ERR(configDirectory.error_occurred(), NULL);
91
JNIStringHolder usernameStr(jusername);
92
if (JNIUtil::isExceptionThrown())
95
JNIStringHolder passwordStr(jpassword);
96
if (JNIUtil::isExceptionThrown())
99
Prompter::UniquePtr prompter(jprompter ? Prompter::create(jprompter)
100
: CompatPrompter::create(jdeprecatedPrompter));
101
if (JNIUtil::isExceptionThrown())
104
jobject jremoteSession = open(
105
jretryAttempts, url.c_str(), uuid,
106
(jconfigDirectory ? configDirectory.c_str() : NULL),
107
usernameStr, passwordStr, prompter, jprogress, jcfgcb, jtunnelcb);
108
if (JNIUtil::isExceptionThrown() || !jremoteSession)
109
jremoteSession = NULL;
110
return jremoteSession;
114
RemoteSession::open(jint jretryAttempts,
115
const char* url, const char* uuid,
116
const char* configDirectory,
117
const char* usernameStr, const char* passwordStr,
118
Prompter::UniquePtr prompter, jobject jprogress,
119
jobject jcfgcb, jobject jtunnelcb)
121
RemoteSession* session = new RemoteSession(
122
jretryAttempts, url, uuid, configDirectory,
123
usernameStr, passwordStr, prompter, jcfgcb, jtunnelcb);
124
if (JNIUtil::isJavaExceptionThrown() || !session)
130
// Create java session object
131
JNIEnv *env = JNIUtil::getEnv();
133
jclass clazz = env->FindClass(JAVA_CLASS_REMOTE_SESSION);
134
if (JNIUtil::isJavaExceptionThrown())
140
static jmethodID ctor = 0;
143
ctor = env->GetMethodID(clazz, "<init>", "(J)V");
144
if (JNIUtil::isJavaExceptionThrown())
151
jobject jremoteSession = env->NewObject(clazz, ctor, session->getCppAddr());
152
if (JNIUtil::isJavaExceptionThrown())
158
session->m_context->activate(jremoteSession, jprogress);
159
if (JNIUtil::isJavaExceptionThrown())
162
jremoteSession = NULL;
165
return jremoteSession;
170
struct compare_c_strings
172
bool operator()(const char* a, const char* b)
174
return (0 < std::strcmp(a, b));
177
typedef std::set<const char*, compare_c_strings> attempt_set;
178
typedef std::pair<attempt_set::iterator, bool> attempt_insert;
179
} // anonymous namespace
181
RemoteSession::RemoteSession(int retryAttempts,
182
const char* url, const char* uuid,
183
const char* configDirectory,
184
const char* username, const char* password,
185
Prompter::UniquePtr prompter,
186
jobject jcfgcb, jobject jtunnelcb)
187
: m_session(NULL), m_context(NULL)
189
m_context = new RemoteSessionContext(
190
pool, configDirectory, username, password, prompter, jcfgcb, jtunnelcb);
191
if (JNIUtil::isJavaExceptionThrown())
194
const char* corrected_url = NULL;
195
bool cycle_detected = false;
196
attempt_set attempted;
198
while (retryAttempts-- >= 0)
201
svn_ra_open4(&m_session, &corrected_url,
202
url, uuid, m_context->getCallbacks(),
203
m_context->getCallbackBaton(),
204
m_context->getConfigData(),
211
attempt_insert result = attempted.insert(corrected_url);
214
cycle_detected = true;
221
JNIEnv *env = JNIUtil::getEnv();
223
jstring exmsg = JNIUtil::makeJString(
224
apr_psprintf(pool.getPool(),
225
_("Redirect cycle detected for URL '%s'"),
228
jclass excls = env->FindClass(
229
JAVAHL_CLASS("/SubversionException"));
230
if (JNIUtil::isJavaExceptionThrown())
233
static jmethodID exctor = 0;
236
exctor = env->GetMethodID(excls, "<init>", "(Ljava/lang/String;)V");
237
if (JNIUtil::isJavaExceptionThrown())
241
jobject ex = env->NewObject(excls, exctor, exmsg);
242
env->Throw(static_cast<jthrowable>(ex));
248
JNIEnv *env = JNIUtil::getEnv();
250
jstring exmsg = JNIUtil::makeJString(_("Too many redirects"));
251
if (JNIUtil::isJavaExceptionThrown())
254
jstring exurl = JNIUtil::makeJString(corrected_url);
255
if (JNIUtil::isJavaExceptionThrown())
258
jclass excls = env->FindClass(
259
JAVAHL_CLASS("/remote/RetryOpenSession"));
260
if (JNIUtil::isJavaExceptionThrown())
263
static jmethodID exctor = 0;
266
exctor = env->GetMethodID(excls, "<init>", "(JJ)V");
267
if (JNIUtil::isJavaExceptionThrown())
271
jobject ex = env->NewObject(excls, exctor, exmsg, exurl);
272
env->Throw(static_cast<jthrowable>(ex));
277
RemoteSession::~RemoteSession()
283
RemoteSession::dispose(jobject jthis)
285
static jfieldID fid = 0;
286
SVNBase::dispose(jthis, &fid, JAVA_CLASS_REMOTE_SESSION);
289
void RemoteSession::reparent(jstring jurl)
291
SVN::Pool subPool(pool);
292
URL url(jurl, subPool);
293
if (JNIUtil::isExceptionThrown())
295
SVN_JNI_ERR(url.error_occurred(),);
297
SVN_JNI_ERR(svn_ra_reparent(m_session, url.c_str(), subPool.getPool()), );
301
RemoteSession::getSessionUrl()
303
SVN::Pool subPool(pool);
305
SVN_JNI_ERR(svn_ra_get_session_url(m_session, &url, subPool.getPool()), NULL);
307
jstring jurl = JNIUtil::makeJString(url);
308
if (JNIUtil::isJavaExceptionThrown())
315
RemoteSession::getSessionRelativePath(jstring jurl)
317
SVN::Pool subPool(pool);
318
URL url(jurl, subPool);
319
if (JNIUtil::isExceptionThrown())
321
SVN_JNI_ERR(url.error_occurred(), NULL);
323
const char* rel_path;
324
SVN_JNI_ERR(svn_ra_get_path_relative_to_session(
325
m_session, &rel_path, url.c_str(), subPool.getPool()),
327
jstring jrel_path = JNIUtil::makeJString(rel_path);
328
if (JNIUtil::isJavaExceptionThrown())
335
RemoteSession::getReposRelativePath(jstring jurl)
337
SVN::Pool subPool(pool);
338
URL url(jurl, subPool);
339
if (JNIUtil::isExceptionThrown())
341
SVN_JNI_ERR(url.error_occurred(), NULL);
343
const char* rel_path;
344
SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &rel_path,
349
jstring jrel_path = JNIUtil::makeJString(rel_path);
350
if (JNIUtil::isJavaExceptionThrown())
357
RemoteSession::getReposUUID()
359
SVN::Pool subPool(pool);
361
SVN_JNI_ERR(svn_ra_get_uuid2(m_session, &uuid, subPool.getPool()), NULL);
363
jstring juuid = JNIUtil::makeJString(uuid);
364
if (JNIUtil::isJavaExceptionThrown())
371
RemoteSession::getReposRootUrl()
373
SVN::Pool subPool(pool);
375
SVN_JNI_ERR(svn_ra_get_repos_root2(m_session, &url, subPool.getPool()),
378
jstring jurl = JNIUtil::makeJString(url);
379
if (JNIUtil::isJavaExceptionThrown())
386
RemoteSession::getLatestRevision()
388
SVN::Pool subPool(pool);
390
SVN_JNI_ERR(svn_ra_get_latest_revnum(m_session, &rev, subPool.getPool()),
396
RemoteSession::getRevisionByTimestamp(jlong timestamp)
398
SVN::Pool subPool(pool);
400
SVN_JNI_ERR(svn_ra_get_dated_revision(m_session, &rev,
401
apr_time_t(timestamp),
409
byte_array_to_svn_string(JNIByteArray& ary, SVN::Pool& scratch_pool)
413
return svn_string_ncreate(reinterpret_cast<const char*>(ary.getBytes()),
414
ary.getLength(), scratch_pool.getPool());
416
} // anonymous namespace
419
RemoteSession::changeRevisionProperty(
420
jlong jrevision, jstring jname,
421
jbyteArray jold_value, jbyteArray jvalue)
423
JNIStringHolder name(jname);
424
if (JNIUtil::isExceptionThrown())
427
JNIByteArray old_value(jold_value);
428
if (JNIUtil::isExceptionThrown())
431
JNIByteArray value(jvalue);
432
if (JNIUtil::isExceptionThrown())
435
SVN::Pool subPool(pool);
436
svn_string_t* const* p_old_value = NULL;
437
svn_string_t* const str_old_value =
438
byte_array_to_svn_string(old_value, subPool);
440
p_old_value = &str_old_value;
442
SVN_JNI_ERR(svn_ra_change_rev_prop2(m_session,
443
svn_revnum_t(jrevision),
445
byte_array_to_svn_string(value, subPool),
446
subPool.getPool()), );
450
RemoteSession::getRevisionProperties(jlong jrevision)
452
SVN::Pool subPool(pool);
454
SVN_JNI_ERR(svn_ra_rev_proplist(m_session, svn_revnum_t(jrevision),
455
&props, subPool.getPool()),
458
return CreateJ::PropertyMap(props, subPool.getPool());
462
RemoteSession::getRevisionProperty(jlong jrevision, jstring jname)
464
JNIStringHolder name(jname);
465
if (JNIUtil::isExceptionThrown())
468
SVN::Pool subPool(pool);
469
svn_string_t *propval;
470
SVN_JNI_ERR(svn_ra_rev_prop(m_session, svn_revnum_t(jrevision),
471
name, &propval, subPool.getPool()),
474
return JNIUtil::makeJByteArray(propval);
478
RemoteSession::getFile(jlong jrevision, jstring jpath,
479
jobject jcontents, jobject jproperties)
481
OutputStream contents_proxy(jcontents);
482
if (JNIUtil::isExceptionThrown())
483
return SVN_INVALID_REVNUM;
485
SVN::Pool subPool(pool);
486
Relpath path(jpath, subPool);
487
if (JNIUtil::isExceptionThrown())
488
return SVN_INVALID_REVNUM;
489
SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
491
apr_hash_t* props = NULL;
492
svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
493
svn_stream_t* contents = (!jcontents ? NULL
494
: contents_proxy.getStream(subPool));
496
SVN_JNI_ERR(svn_ra_get_file(m_session, path.c_str(), fetched_rev,
497
contents, &fetched_rev,
498
(jproperties ? &props : NULL),
504
CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
505
if (JNIUtil::isExceptionThrown())
506
return SVN_INVALID_REVNUM;
513
void fill_dirents(const char* base_url, const char* base_relpath,
514
jobject jdirents, apr_hash_t* dirents,
515
apr_pool_t* scratch_pool)
520
base_url = apr_pstrcat(scratch_pool, base_url, "/", base_relpath, NULL);
521
base_url = svn_uri_canonicalize(base_url, scratch_pool);
522
svn_stringbuf_t* abs_path = svn_stringbuf_create(base_url, scratch_pool);
523
svn_stringbuf_appendbyte(abs_path, '/');
524
const apr_size_t base_len = abs_path->len;
526
JNIEnv *env = JNIUtil::getEnv();
528
// Create a local frame for our references
529
env->PushLocalFrame(LOCAL_FRAME_SIZE);
530
if (JNIUtil::isJavaExceptionThrown())
533
// We have no way of knowing the exact type of `dirents' in advance
534
// so we cannot remember the "put" method ID across calls.
536
env->GetMethodID(env->GetObjectClass(jdirents), "put",
537
"(Ljava/lang/Object;Ljava/lang/Object;)"
538
"Ljava/lang/Object;");
539
if (JNIUtil::isJavaExceptionThrown())
540
POP_AND_RETURN_NOTHING();
542
static jfieldID path_fid = 0;
545
jclass clazz = env->FindClass(JAVAHL_CLASS("/types/DirEntry"));
546
if (JNIUtil::isJavaExceptionThrown())
547
POP_AND_RETURN_NOTHING();
549
path_fid = env->GetFieldID(clazz, "path", "Ljava/lang/String;");
550
if (JNIUtil::isJavaExceptionThrown())
551
POP_AND_RETURN_NOTHING();
554
for (apr_hash_index_t* hi = apr_hash_first(scratch_pool, dirents);
555
hi; hi = apr_hash_next(hi))
558
svn_dirent_t* dirent;
563
apr_hash_this(hi, &v_key, NULL, &v_val);
564
path = static_cast<const char*>(v_key);
565
dirent = static_cast<svn_dirent_t*>(v_val);
566
abs_path->len = base_len;
567
svn_stringbuf_appendcstr(abs_path, path);
569
jobject jdirent = CreateJ::DirEntry(path, abs_path->data, dirent);
570
if (JNIUtil::isJavaExceptionThrown())
571
POP_AND_RETURN_NOTHING();
573
// Use the existing DirEntry.path field as the key
574
jstring jpath = jstring(env->GetObjectField(jdirent, path_fid));
575
if (JNIUtil::isJavaExceptionThrown())
576
POP_AND_RETURN_NOTHING();
578
env->CallObjectMethod(jdirents, put_mid, jpath, jdirent);
579
if (JNIUtil::isJavaExceptionThrown())
580
POP_AND_RETURN_NOTHING();
581
env->DeleteLocalRef(jdirent);
584
POP_AND_RETURN_NOTHING();
586
} // anonymous namespace
589
RemoteSession::getDirectory(jlong jrevision, jstring jpath,
590
jint jdirent_fields, jobject jdirents,
593
SVN::Pool subPool(pool);
594
Relpath path(jpath, subPool);
595
if (JNIUtil::isExceptionThrown())
596
return SVN_INVALID_REVNUM;
597
SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
599
apr_hash_t* props = NULL;
600
apr_hash_t* dirents = NULL;
601
svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
603
SVN_JNI_ERR(svn_ra_get_dir2(m_session, (jdirents ? &dirents : NULL),
604
&fetched_rev, (jproperties ? &props : NULL),
605
path.c_str(), fetched_rev,
606
apr_uint32_t(jdirent_fields),
612
// We will construct the absolute path in the DirEntry objects
613
// from the session URL and directory relpath.
614
const char* base_url;
615
SVN_JNI_ERR(svn_ra_get_session_url(m_session, &base_url,
618
fill_dirents(base_url, path.c_str(), jdirents, dirents,
620
if (JNIUtil::isExceptionThrown())
621
return SVN_INVALID_REVNUM;
626
CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
627
if (JNIUtil::isExceptionThrown())
628
return SVN_INVALID_REVNUM;
635
const apr_array_header_t*
636
build_string_array(const Iterator& iter,
637
bool contains_relpaths, SVN::Pool& pool)
639
apr_pool_t* result_pool = pool.getPool();
640
apr_array_header_t* array = apr_array_make(
641
result_pool, 0, sizeof(const char*));
642
while (iter.hasNext())
645
jstring jitem = (jstring)iter.next();
646
if (contains_relpaths)
648
Relpath item(jitem, pool);
649
if (JNIUtil::isExceptionThrown())
651
SVN_JNI_ERR(item.error_occurred(), NULL);
652
element = apr_pstrdup(result_pool, item.c_str());
656
JNIStringHolder item(jitem);
657
if (JNIUtil::isJavaExceptionThrown())
659
element = item.pstrdup(result_pool);
661
APR_ARRAY_PUSH(array, const char*) = element;
668
RemoteSession::getMergeinfo(jobject jpaths, jlong jrevision, jobject jinherit,
669
jboolean jinclude_descendants)
671
Iterator paths_iter(jpaths);
672
if (JNIUtil::isExceptionThrown())
675
SVN::Pool subPool(pool);
676
const apr_array_header_t* paths =
677
build_string_array(paths_iter, true, subPool);
678
if (JNIUtil::isJavaExceptionThrown())
681
svn_mergeinfo_catalog_t catalog;
682
SVN_JNI_ERR(svn_ra_get_mergeinfo(
683
m_session, &catalog, paths, svn_revnum_t(jrevision),
684
EnumMapper::toMergeinfoInheritance(jinherit),
685
bool(jinclude_descendants),
691
JNIEnv* env = JNIUtil::getEnv();
692
jclass cls = env->FindClass("java/util/HashMap");
693
if (JNIUtil::isExceptionThrown())
696
static jmethodID ctor_mid = 0;
699
ctor_mid = env->GetMethodID(cls, "<init>", "()V");
700
if (JNIUtil::isExceptionThrown())
704
static jmethodID put_mid = 0;
707
put_mid = env->GetMethodID(cls, "put",
708
"(Ljava/lang/Object;"
709
"Ljava/lang/Object;)"
710
"Ljava/lang/Object;");
711
if (JNIUtil::isExceptionThrown())
715
jobject jcatalog = env->NewObject(cls, ctor_mid);
716
if (JNIUtil::isExceptionThrown())
719
for (apr_hash_index_t* hi = apr_hash_first(subPool.getPool(), catalog);
720
hi; hi = apr_hash_next(hi))
724
apr_hash_this(hi, &v_key, NULL, &v_val);
725
const char* key = static_cast<const char*>(v_key);
726
svn_mergeinfo_t val = static_cast<svn_mergeinfo_t>(v_val);
728
jstring jpath = JNIUtil::makeJString(key);
729
if (JNIUtil::isExceptionThrown())
731
jobject jmergeinfo = CreateJ::Mergeinfo(val, subPool.getPool());
732
if (JNIUtil::isExceptionThrown())
735
env->CallObjectMethod(jcatalog, put_mid, jpath, jmergeinfo);
736
if (JNIUtil::isExceptionThrown())
739
env->DeleteLocalRef(jpath);
740
env->DeleteLocalRef(jmergeinfo);
751
status_unlock_func(void* baton, const char* path, apr_pool_t* scratch_pool)
753
//DEBUG:fprintf(stderr, " (n) status_unlock_func('%s')\n", path);
758
status_fetch_props_func(apr_hash_t **props, void *baton,
759
const char *path, svn_revnum_t base_revision,
760
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
762
//DEBUG:fprintf(stderr, " (n) status_fetch_props_func('%s', r%lld)\n",
763
//DEBUG: path, static_cast<long long>(base_revision));
764
*props = apr_hash_make(result_pool);
769
status_fetch_base_func(const char **filename, void *baton,
770
const char *path, svn_revnum_t base_revision,
771
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
773
//DEBUG:fprintf(stderr, " (n) status_fetch_base_func('%s', r%lld)\n",
774
//DEBUG: path, static_cast<long long>(base_revision));
780
status_start_edit_func(void* baton, svn_revnum_t start_revision)
782
//DEBUG:fprintf(stderr, " (n) status_start_edit_func(r%lld)\n",
783
//DEBUG: static_cast<long long>(start_revision));
788
status_target_revision_func(void* baton, svn_revnum_t target_revision,
789
apr_pool_t* scratch_pool)
791
//DEBUG:fprintf(stderr, " (n) status_target_revision_func(r%lld)\n",
792
//DEBUG: static_cast<long long>(target_revision));
793
*static_cast<svn_revnum_t*>(baton) = target_revision;
797
const EditorProxyCallbacks template_status_editor_callbacks = {
799
status_fetch_props_func,
800
status_fetch_base_func,
801
{ status_start_edit_func, status_target_revision_func, NULL },
804
} // anonymous namespace
807
RemoteSession::status(jobject jthis, jstring jstatus_target,
808
jlong jrevision, jobject jdepth,
809
jobject jstatus_editor, jobject jreporter)
811
StateReporter *rp = StateReporter::getCppObject(jreporter);
812
CPPADDR_NULL_PTR(rp,);
814
SVN::Pool scratchPool(rp->get_report_pool());
815
Relpath status_target(jstatus_target, scratchPool);
816
if (JNIUtil::isExceptionThrown())
819
apr_pool_t* scratch_pool = scratchPool.getPool();
820
const char* repos_root_url;
821
SVN_JNI_ERR(svn_ra_get_repos_root2(m_session, &repos_root_url,
823
const char* session_root_url;
824
SVN_JNI_ERR(svn_ra_get_session_url(m_session, &session_root_url,
826
const char* base_relpath;
827
SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &base_relpath,
831
EditorProxyCallbacks proxy_callbacks =
832
template_status_editor_callbacks;
833
proxy_callbacks.m_extra_baton.baton = &rp->m_target_revision;
835
apr_pool_t* report_pool = rp->get_report_pool();
836
std::auto_ptr<EditorProxy> editor(
837
new EditorProxy(jstatus_editor, report_pool,
838
repos_root_url, base_relpath,
839
m_context->checkCancel, m_context,
841
if (JNIUtil::isExceptionThrown())
844
const svn_ra_reporter3_t* raw_reporter;
846
SVN_JNI_ERR(svn_ra_do_status2(m_session,
847
&raw_reporter, &report_baton,
848
status_target.c_str(),
849
svn_revnum_t(jrevision),
850
EnumMapper::toDepth(jdepth),
851
editor->delta_editor(),
852
editor->delta_baton(),
854
rp->set_reporter_data(raw_reporter, report_baton, editor.release());
860
RemoteSession::getLog(jobject jpaths,
861
jlong jstartrev, jlong jendrev, jint jlimit,
862
jboolean jstrict_node_history,
863
jboolean jdiscover_changed_paths,
864
jboolean jinclude_merged_revisions,
865
jobject jrevprops, jobject jlog_callback)
867
Iterator pathiter(jpaths);
868
if (JNIUtil::isJavaExceptionThrown())
870
Iterator revpropiter(jrevprops);
871
if (JNIUtil::isJavaExceptionThrown())
873
LogMessageCallback receiver(jlog_callback);
875
SVN::Pool subPool(pool);
876
const apr_array_header_t* paths = build_string_array(pathiter,
878
if (JNIUtil::isJavaExceptionThrown())
880
const apr_array_header_t* revprops = (jrevprops != NULL)
881
? build_string_array(revpropiter,
884
if (JNIUtil::isJavaExceptionThrown())
887
SVN_JNI_ERR(svn_ra_get_log2(m_session, paths,
888
svn_revnum_t(jstartrev), svn_revnum_t(jendrev),
890
bool(jdiscover_changed_paths),
891
bool(jstrict_node_history),
892
bool(jinclude_merged_revisions),
894
receiver.callback, &receiver,
895
subPool.getPool()),);
899
RemoteSession::checkPath(jstring jpath, jlong jrevision)
901
SVN::Pool subPool(pool);
902
Relpath path(jpath, subPool);
903
if (JNIUtil::isExceptionThrown())
905
SVN_JNI_ERR(path.error_occurred(), NULL);
907
svn_node_kind_t kind;
908
SVN_JNI_ERR(svn_ra_check_path(m_session, path.c_str(),
909
svn_revnum_t(jrevision),
910
&kind, subPool.getPool()),
913
return EnumMapper::mapNodeKind(kind);
917
RemoteSession::stat(jstring jpath, jlong jrevision)
919
SVN::Pool subPool(pool);
920
Relpath path(jpath, subPool);
921
if (JNIUtil::isExceptionThrown())
923
SVN_JNI_ERR(path.error_occurred(), NULL);
925
svn_dirent_t* dirent;
926
SVN_JNI_ERR(svn_ra_stat(m_session, path.c_str(),
927
svn_revnum_t(jrevision),
928
&dirent, subPool.getPool()),
932
return CreateJ::DirEntry(path.c_str(), path.c_str(), dirent);
938
long_iterable_to_revnum_array(jobject jlong_iterable, apr_pool_t* pool)
941
JNIEnv* env = JNIUtil::getEnv();
943
jclass cls = env->FindClass("java/lang/Long");
944
if (JNIUtil::isExceptionThrown())
947
static jmethodID mid = 0;
950
mid = env->GetMethodID(cls, "longValue", "()J");
951
if (JNIUtil::isExceptionThrown())
955
apr_array_header_t* array = apr_array_make(pool, 0, sizeof(svn_revnum_t));
956
Iterator iter(jlong_iterable);
957
while (iter.hasNext())
959
const jlong entry = env->CallLongMethod(iter.next(), mid);
960
if (JNIUtil::isExceptionThrown())
962
APR_ARRAY_PUSH(array, svn_revnum_t) = svn_revnum_t(entry);
968
location_hash_to_map(apr_hash_t* locations, apr_pool_t* scratch_pool)
970
JNIEnv* env = JNIUtil::getEnv();
972
jclass long_cls = env->FindClass("java/lang/Long");
973
if (JNIUtil::isExceptionThrown())
976
static jmethodID long_ctor = 0;
979
long_ctor = env->GetMethodID(long_cls, "<init>", "(J)V");
980
if (JNIUtil::isExceptionThrown())
984
jclass hash_cls = env->FindClass("java/util/HashMap");
985
if (JNIUtil::isExceptionThrown())
988
static jmethodID hash_ctor = 0;
991
hash_ctor = env->GetMethodID(hash_cls, "<init>", "()V");
992
if (JNIUtil::isExceptionThrown())
996
static jmethodID hash_put = 0;
999
hash_put = env->GetMethodID(hash_cls, "put",
1000
"(Ljava/lang/Object;Ljava/lang/Object;"
1001
")Ljava/lang/Object;");
1002
if (JNIUtil::isExceptionThrown())
1006
jobject result = env->NewObject(hash_cls, hash_ctor);
1007
if (JNIUtil::isExceptionThrown())
1013
for (apr_hash_index_t* hi = apr_hash_first(scratch_pool, locations);
1014
hi; hi = apr_hash_next(hi))
1019
apr_hash_this(hi, &key, NULL, &val);
1021
jobject jkey = env->NewObject(
1022
long_cls, long_ctor, jlong(*static_cast<const svn_revnum_t*>(key)));
1023
if (JNIUtil::isExceptionThrown())
1025
jstring jval = JNIUtil::makeJString(static_cast<const char*>(val));
1026
if (JNIUtil::isExceptionThrown())
1029
env->CallObjectMethod(result, hash_put, jkey, jval);
1030
if (JNIUtil::isExceptionThrown())
1033
env->DeleteLocalRef(jkey);
1034
env->DeleteLocalRef(jval);
1039
} // anonymous namespace
1042
RemoteSession::getLocations(jstring jpath, jlong jpeg_revision,
1043
jobject jlocation_revisions)
1045
if (!jpath || !jlocation_revisions)
1048
SVN::Pool subPool(pool);
1049
Relpath path(jpath, subPool);
1050
if (JNIUtil::isExceptionThrown())
1052
SVN_JNI_ERR(path.error_occurred(), NULL);
1054
apr_array_header_t* location_revisions =
1055
long_iterable_to_revnum_array(jlocation_revisions, subPool.getPool());
1056
if (!location_revisions)
1059
apr_hash_t* locations;
1060
SVN_JNI_ERR(svn_ra_get_locations(m_session, &locations,
1061
path.c_str(), svn_revnum_t(jpeg_revision),
1062
location_revisions, subPool.getPool()),
1064
return location_hash_to_map(locations, subPool.getPool());
1068
class LocationSegmentHandler
1071
static svn_error_t* callback(svn_location_segment_t* segment,
1072
void* baton, apr_pool_t*)
1074
LocationSegmentHandler* const self =
1075
static_cast<LocationSegmentHandler*>(baton);
1076
SVN_ERR_ASSERT(self->m_jcallback != NULL);
1077
self->call(segment);
1078
SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
1079
return SVN_NO_ERROR;
1082
LocationSegmentHandler(jobject jcallback)
1083
: m_jcallback(jcallback),
1086
JNIEnv* env = JNIUtil::getEnv();
1087
jclass cls = env->GetObjectClass(jcallback);
1088
if (JNIUtil::isJavaExceptionThrown())
1091
m_call_mid = env->GetMethodID(
1092
cls, "doSegment", "(" JAVAHL_ARG("/ISVNRemote$LocationSegment;") ")V");
1093
if (JNIUtil::isJavaExceptionThrown())
1098
void call(svn_location_segment_t* segment)
1100
JNIEnv* env = JNIUtil::getEnv();
1101
jclass cls = env->FindClass(JAVAHL_CLASS("/ISVNRemote$LocationSegment"));
1102
if (JNIUtil::isJavaExceptionThrown())
1105
static jmethodID mid = 0;
1108
mid = env->GetMethodID(cls, "<init>",
1109
"(Ljava/lang/String;JJ)V");
1110
if (JNIUtil::isJavaExceptionThrown())
1114
jstring jpath = JNIUtil::makeJString(segment->path);
1115
if (JNIUtil::isJavaExceptionThrown())
1118
env->CallVoidMethod(m_jcallback, m_call_mid,
1119
env->NewObject(cls, mid, jpath,
1120
jlong(segment->range_start),
1121
jlong(segment->range_end)));
1122
if (JNIUtil::isJavaExceptionThrown())
1124
env->DeleteLocalRef(jpath);
1127
jobject m_jcallback;
1128
jmethodID m_call_mid;
1130
} // anonymous namespace
1133
RemoteSession::getLocationSegments(jstring jpath, jlong jpeg_revision,
1134
jlong jstart_revision, jlong jend_revision,
1137
SVN::Pool subPool(pool);
1138
Relpath path(jpath, subPool);
1139
if (JNIUtil::isExceptionThrown())
1141
SVN_JNI_ERR(path.error_occurred(), );
1143
LocationSegmentHandler handler(jcallback);
1144
if (JNIUtil::isExceptionThrown())
1147
SVN_JNI_ERR(svn_ra_get_location_segments(m_session, path.c_str(),
1148
svn_revnum_t(jpeg_revision),
1149
svn_revnum_t(jstart_revision),
1150
svn_revnum_t(jend_revision),
1151
handler.callback, &handler,
1152
subPool.getPool()),);
1156
class FileRevisionHandler
1159
static svn_error_t* callback(void* baton,
1160
const char* path, svn_revnum_t revision,
1161
apr_hash_t* revision_props,
1162
// We ignore the deltas as they're not
1163
// exposed in the JavaHL API.
1164
svn_boolean_t result_of_merge,
1165
svn_txdelta_window_handler_t* delta_handler,
1166
void** delta_handler_baton,
1167
apr_array_header_t* prop_diffs,
1168
apr_pool_t* scratch_pool)
1171
*delta_handler = svn_delta_noop_window_handler;
1172
if (delta_handler_baton)
1173
*delta_handler_baton = NULL;
1175
FileRevisionHandler* const self =
1176
static_cast<FileRevisionHandler*>(baton);
1177
SVN_ERR_ASSERT(self->m_jcallback != NULL);
1178
self->call(path, revision, revision_props,
1179
result_of_merge, prop_diffs,
1180
(delta_handler != NULL),
1182
SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
1183
return SVN_NO_ERROR;
1186
FileRevisionHandler(jobject jcallback)
1187
: m_jcallback(jcallback),
1190
JNIEnv* env = JNIUtil::getEnv();
1191
jclass cls = env->GetObjectClass(jcallback);
1192
if (JNIUtil::isJavaExceptionThrown())
1195
m_call_mid = env->GetMethodID(
1196
cls, "doRevision", "(" JAVAHL_ARG("/ISVNRemote$FileRevision;") ")V");
1197
if (JNIUtil::isJavaExceptionThrown())
1202
void call(const char* path, svn_revnum_t revision,
1203
apr_hash_t* revision_props,
1204
svn_boolean_t result_of_merge,
1205
apr_array_header_t* prop_diffs,
1206
svn_boolean_t has_text_delta,
1207
apr_pool_t* scratch_pool)
1209
JNIEnv* env = JNIUtil::getEnv();
1210
jclass cls = env->FindClass(JAVAHL_CLASS("/ISVNRemote$FileRevision"));
1211
if (JNIUtil::isJavaExceptionThrown())
1214
static jmethodID mid = 0;
1217
mid = env->GetMethodID(cls, "<init>",
1218
"(Ljava/lang/String;JZ"
1219
"Ljava/util/Map;Ljava/util/Map;Z)V");
1220
if (JNIUtil::isJavaExceptionThrown())
1224
jstring jpath = JNIUtil::makeJString(path);
1225
if (JNIUtil::isJavaExceptionThrown())
1227
jobject jrevprops = CreateJ::PropertyMap(revision_props, scratch_pool);
1228
if (JNIUtil::isJavaExceptionThrown())
1230
jobject jpropdelta = CreateJ::PropertyMap(prop_diffs, scratch_pool);
1231
if (JNIUtil::isJavaExceptionThrown())
1234
env->CallVoidMethod(m_jcallback, m_call_mid,
1235
env->NewObject(cls, mid, jpath, jlong(revision),
1236
jboolean(result_of_merge),
1237
jrevprops, jpropdelta,
1238
jboolean(has_text_delta)));
1239
if (JNIUtil::isJavaExceptionThrown())
1241
env->DeleteLocalRef(jpath);
1242
env->DeleteLocalRef(jrevprops);
1243
env->DeleteLocalRef(jpropdelta);
1246
jobject m_jcallback;
1247
jmethodID m_call_mid;
1249
} // anonymous namespace
1252
RemoteSession::getFileRevisions(jstring jpath,
1253
jlong jstart_revision, jlong jend_revision,
1254
jboolean jinclude_merged_revisions,
1257
SVN::Pool subPool(pool);
1258
Relpath path(jpath, subPool);
1259
if (JNIUtil::isExceptionThrown())
1261
SVN_JNI_ERR(path.error_occurred(), );
1263
FileRevisionHandler handler(jcallback);
1264
if (JNIUtil::isExceptionThrown())
1267
SVN_JNI_ERR(svn_ra_get_file_revs2(m_session, path.c_str(),
1268
svn_revnum_t(jstart_revision),
1269
svn_revnum_t(jend_revision),
1270
bool(jinclude_merged_revisions),
1271
handler.callback, &handler,
1272
subPool.getPool()),);
1280
RemoteSession::getLocks(jstring jpath, jobject jdepth)
1282
svn_depth_t depth = EnumMapper::toDepth(jdepth);
1283
if (JNIUtil::isExceptionThrown())
1286
SVN::Pool subPool(pool);
1287
Relpath path(jpath, subPool);
1288
if (JNIUtil::isExceptionThrown())
1290
SVN_JNI_ERR(path.error_occurred(), NULL);
1293
SVN_JNI_ERR(svn_ra_get_locks2(m_session, &locks, path.c_str(), depth,
1297
return CreateJ::LockMap(locks, subPool.getPool());
1300
// TODO: replayRange
1302
// TODO: getDeletedRevision
1303
// TODO: getInheritedProperties
1306
RemoteSession::hasCapability(jstring jcapability)
1308
JNIStringHolder capability(jcapability);
1309
if (JNIUtil::isExceptionThrown())
1312
SVN::Pool subPool(pool);
1314
SVN_JNI_ERR(svn_ra_has_capability(m_session, &has, capability,
1318
return jboolean(has);