1 /**
2 * @copyright
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
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
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
19 * under the License.
20 * ====================================================================
21 * @endcopyright
22 */
23
24 #include <stdexcept>
25
26 #include <apr_atomic.h>
27
28 #define SVN_JAVAHL_JNIWRAPPER_LOG(expr)
29 #include "jni_env.hpp"
30 #include "jni_globalref.hpp"
31 #include "jni_exception.hpp"
32 #include "jni_object.hpp"
33 #include "jni_string.hpp"
34
35 #include "jni_channel.hpp"
36 #include "jni_io_stream.hpp"
37 #include "jni_list.hpp"
38 #include "jni_string_map.hpp"
39
40 #include "../SubversionException.hpp"
41 #include "../AuthnCallback.hpp"
42 #include "../Credential.hpp"
43 #include "../ExternalItem.hpp"
44 #include "../EditorCallbacks.hpp"
45 #include "../CxxCompat.hpp"
46
47 namespace
48 {
49 /* This class behaves like a dumbed-down std:unique_ptr, but it
50 implements atomic access and modification of the wrapped
51 pointer. */
52 class ClassImplPtr
53 {
54 typedef ::Java::Object::ClassImpl ClassImpl;
55
56 public:
57 /* Default constructor; initializes the wrapped pointer to NULL */
ClassImplPtr()58 explicit ClassImplPtr()
59 : m_ptr(NULL)
60 {}
61
62 /* Initializing constructor; sets the wrapped pointer to PTR */
ClassImplPtr(ClassImpl * ptr)63 explicit ClassImplPtr(ClassImpl* ptr)
64 : m_ptr(ptr)
65 {}
66
67 /* Destructor deletes the object and resets the wrapped pointer to NULL. */
~ClassImplPtr()68 ~ClassImplPtr()
69 {
70 delete static_cast<ClassImpl*>(
71 apr_atomic_casptr(&m_ptr, NULL, get()));
72 }
73
74 /* Sets the wrapped pointer to PTR iff it is NULL, and returns the
75 old value. */
test_and_set(ClassImpl * ptr)76 ClassImpl* test_and_set(ClassImpl* ptr)
77 {
78 return static_cast<ClassImpl*>(
79 apr_atomic_casptr(&m_ptr, ptr, NULL));
80 }
81
82 /* Returns the current value of the the wrapped pointer. */
get() const83 ClassImpl* get() const
84 {
85 return static_cast<ClassImpl*>(
86 apr_atomic_casptr(&m_ptr, NULL, NULL));
87 }
88
89 private:
90 // Non-copyable
91 ClassImplPtr(const ClassImplPtr&);
92 ClassImplPtr& operator=(const ClassImplPtr&);
93
94 mutable volatile void* m_ptr;
95 };
96 } // anonymous namespace
97
98
99 namespace Java {
100
101 class ClassCacheImpl
102 {
103
104 friend class ClassCache;
105
106 // We only statically initialize a few of the common class wrappers.
ClassCacheImpl(Env env)107 explicit ClassCacheImpl(Env env) :
108
109 #define JNIWRAPPER_INIT_CACHED_CLASS(M, C) \
110 m_impl_##M(new C::ClassImpl(env, env.FindClass(C::m_class_name)))
111
112 JNIWRAPPER_INIT_CACHED_CLASS(object, Object),
113 JNIWRAPPER_INIT_CACHED_CLASS(classtype, Class),
114 JNIWRAPPER_INIT_CACHED_CLASS(throwable, Exception),
115 JNIWRAPPER_INIT_CACHED_CLASS(string, String)
116 #undef JNIWRAPPER_INIT_CACHED_CLASS
117 {}
118
119 // We can't do this in the constructor above, because the satic
120 // initializers will expect that ClassCache::m_impl is already set;
121 // that doesn't happen until the constructor returns.
static_init(Env env)122 void static_init(Env env)
123 {
124 #define JNIWRAPPER_STATIC_CACHED_CLASS(M, C) \
125 C::static_init(env, m_impl_##M->get_class())
126
127 // No-op JNIWRAPPER_STATIC_CACHED_CLASS(object, Object);
128 JNIWRAPPER_STATIC_CACHED_CLASS(classtype, Class);
129 JNIWRAPPER_STATIC_CACHED_CLASS(throwable, Exception);
130 // No-op JNIWRAPPER_STATIC_CACHED_CLASS(string, String);
131 #undef JNIWRAPPER_STATIC_CACHED_CLASS
132 }
133
134 // The statically initialized calss wrappers are always defined and
135 // therefore do not need atomic access.
136 #define JNIWRAPPER_DEFINE_CACHED_CLASS(M, C) \
137 JavaHL::cxx::owned_ptr<Object::ClassImpl> m_impl_##M; \
138 const Object::ClassImpl* get_##M(Env) \
139 { \
140 return m_impl_##M.get(); \
141 }
142
143 JNIWRAPPER_DEFINE_CACHED_CLASS(object, Object)
144 JNIWRAPPER_DEFINE_CACHED_CLASS(classtype, Class)
145 JNIWRAPPER_DEFINE_CACHED_CLASS(throwable, Exception)
146 JNIWRAPPER_DEFINE_CACHED_CLASS(string, String)
147 #undef JNIWRAPPER_DEFINE_CACHED_CLASS
148
149 // All other class wrappers must be atomically initialized
150 #define JNIWRAPPER_DEFINE_CACHED_CLASS(M, C) \
151 ClassImplPtr m_impl_##M; \
152 const Object::ClassImpl* get_##M(Env env) \
153 { \
154 Object::ClassImpl* pimpl = m_impl_##M.get(); \
155 if (!pimpl) \
156 { \
157 JavaHL::cxx::owned_ptr<Object::ClassImpl> tmp( \
158 new C::ClassImpl( \
159 env, env.FindClass(C::m_class_name))); \
160 pimpl = m_impl_##M.test_and_set(tmp.get()); \
161 if (!pimpl) \
162 pimpl = tmp.release(); \
163 } \
164 return pimpl; \
165 }
166
167 JNIWRAPPER_DEFINE_CACHED_CLASS(exc_index_out_of_bounds,
168 IndexOutOfBoundsException);
169 JNIWRAPPER_DEFINE_CACHED_CLASS(exc_no_such_element,
170 NoSuchElementException);
171
172 JNIWRAPPER_DEFINE_CACHED_CLASS(iterator, BaseIterator);
173
174 JNIWRAPPER_DEFINE_CACHED_CLASS(list, BaseImmutableList);
175 JNIWRAPPER_DEFINE_CACHED_CLASS(array_list, BaseList);
176
177 JNIWRAPPER_DEFINE_CACHED_CLASS(map, BaseImmutableMap);
178 JNIWRAPPER_DEFINE_CACHED_CLASS(set, BaseImmutableMap::Set);
179 JNIWRAPPER_DEFINE_CACHED_CLASS(map_entry, BaseImmutableMap::Entry);
180 JNIWRAPPER_DEFINE_CACHED_CLASS(hash_map, BaseMap);
181
182 JNIWRAPPER_DEFINE_CACHED_CLASS(input_stream, InputStream);
183 JNIWRAPPER_DEFINE_CACHED_CLASS(output_stream, OutputStream);
184
185 JNIWRAPPER_DEFINE_CACHED_CLASS(byte_buffer,
186 ByteChannel::ByteBuffer);
187
188 JNIWRAPPER_DEFINE_CACHED_CLASS(subversion_exception,
189 ::JavaHL::SubversionException);
190
191 JNIWRAPPER_DEFINE_CACHED_CLASS(authn_cb,
192 ::JavaHL::AuthnCallback);
193 JNIWRAPPER_DEFINE_CACHED_CLASS(authn_result,
194 ::JavaHL::AuthnCallback::AuthnResult);
195 JNIWRAPPER_DEFINE_CACHED_CLASS(authn_ssl_server_cert_failures,
196 ::JavaHL::AuthnCallback::SSLServerCertFailures);
197 JNIWRAPPER_DEFINE_CACHED_CLASS(authn_ssl_server_cert_info,
198 ::JavaHL::AuthnCallback::SSLServerCertInfo);
199 JNIWRAPPER_DEFINE_CACHED_CLASS(user_passwd_cb,
200 ::JavaHL::UserPasswordCallback);
201
202 JNIWRAPPER_DEFINE_CACHED_CLASS(credential,
203 ::JavaHL::Credential);
204 JNIWRAPPER_DEFINE_CACHED_CLASS(credential_kind,
205 ::JavaHL::Credential::Kind);
206
207 JNIWRAPPER_DEFINE_CACHED_CLASS(external_item,
208 ::JavaHL::ExternalItem);
209
210 JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_base_cb,
211 ::JavaHL::ProvideBaseCallback);
212 JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_base_cb_ret,
213 ::JavaHL::ProvideBaseCallback::ReturnValue);
214 JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_props_cb,
215 ::JavaHL::ProvidePropsCallback);
216 JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_props_cb_ret,
217 ::JavaHL::ProvidePropsCallback::ReturnValue);
218 JNIWRAPPER_DEFINE_CACHED_CLASS(editor_get_kind_cb,
219 ::JavaHL::GetNodeKindCallback);
220 #undef JNIWRAPPER_DEFINE_CACHED_CLASS
221 };
222
223
224 ClassCacheImpl* ClassCache::m_impl = NULL;
225
create()226 void ClassCache::create()
227 {
228 const char* exception_message = NULL;
229
230 try
231 {
232 const Env env;
233 m_impl = new ClassCacheImpl(env);
234 m_impl->static_init(env);
235 }
236 catch (const SignalExceptionThrown&)
237 {}
238 catch (const std::exception& ex)
239 {
240 exception_message = ex.what();
241 }
242 catch (...)
243 {
244 exception_message = "Caught unknown C++ exception";
245 }
246
247 // Do not throw any more exceptions from here, so use the raw environment.
248 ::JNIEnv* const jenv = Env().get();
249 if (exception_message || jenv->ExceptionCheck())
250 {
251 jobject cause = jenv->ExceptionOccurred();
252 if (cause)
253 jenv->ExceptionClear();
254
255 const jclass rtx = jenv->FindClass("java/lang/RuntimeException");
256 const jmethodID ctor = jenv->GetMethodID(rtx, "<init>",
257 "(Ljava/lang/String;"
258 "Ljava/lang/Throwable;)V");
259 if (!cause && exception_message)
260 {
261 const jstring msg = jenv->NewStringUTF(exception_message);
262 cause = jenv->NewObject(rtx, ctor, msg, jthrowable(0));
263 }
264 const jstring reason =
265 jenv->NewStringUTF("JavaHL native library initialization failed");
266 const jobject exception = jenv->NewObject(rtx, ctor, reason, cause);
267 jenv->Throw(jthrowable(exception));
268 }
269 }
270
destroy()271 void ClassCache::destroy()
272 {
273 ClassCacheImpl* const pimpl = m_impl;
274 m_impl = NULL;
275 delete pimpl;
276 }
277
278 #define JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(M) \
279 const Object::ClassImpl* ClassCache::get_##M(Env env) \
280 { \
281 return m_impl->get_##M(env); \
282 }
283
284 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(object);
285 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(classtype);
286 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(throwable);
287 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(string);
288
289 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(exc_index_out_of_bounds);
290 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(exc_no_such_element);
291
292 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(list);
293 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(array_list);
294
295 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(map);
296 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(set);
297 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(iterator);
298 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(map_entry);
299 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(hash_map);
300
301 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(input_stream);
302 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(output_stream);
303
304 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(byte_buffer);
305
306 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(subversion_exception);
307
308 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_cb);
309 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_result);
310 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_ssl_server_cert_failures);
311 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_ssl_server_cert_info);
312 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(user_passwd_cb);
313
314
315 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(credential);
316 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(credential_kind);
317
318 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(external_item);
319
320 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_base_cb);
321 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_base_cb_ret);
322 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_props_cb);
323 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_props_cb_ret);
324 JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_get_kind_cb);
325 #undef JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR
326
327 } // namespace Java
328