summaryrefslogtreecommitdiff
path: root/subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp')
-rw-r--r--subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp b/subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp
new file mode 100644
index 0000000..9e533db
--- /dev/null
+++ b/subversion/bindings/javahl/native/jniwrapper/jni_class_cache.cpp
@@ -0,0 +1,326 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include <stdexcept>
+
+#include <apr_atomic.h>
+
+#define SVN_JAVAHL_JNIWRAPPER_LOG(expr)
+#include "jni_env.hpp"
+#include "jni_globalref.hpp"
+#include "jni_exception.hpp"
+#include "jni_object.hpp"
+#include "jni_string.hpp"
+
+#include "jni_channel.hpp"
+#include "jni_io_stream.hpp"
+#include "jni_list.hpp"
+#include "jni_string_map.hpp"
+
+#include "../SubversionException.hpp"
+#include "../AuthnCallback.hpp"
+#include "../Credential.hpp"
+#include "../ExternalItem.hpp"
+#include "../EditorCallbacks.hpp"
+
+namespace
+{
+/* This class behaves like a dumbed-down std:auto_ptr, but it
+ implements atomic access and modification of the wrapped
+ pointer. */
+class ClassImplPtr
+{
+ typedef ::Java::Object::ClassImpl ClassImpl;
+
+ public:
+ /* Default constructor; initializes the wrapped pointer to NULL */
+ explicit ClassImplPtr()
+ : m_ptr(NULL)
+ {}
+
+ /* Initializing constructor; sets the wrapped pointer to PTR */
+ explicit ClassImplPtr(ClassImpl* ptr)
+ : m_ptr(ptr)
+ {}
+
+ /* Destructor deletes the object and resets the wrapped pointer to NULL. */
+ ~ClassImplPtr()
+ {
+ delete static_cast<ClassImpl*>(
+ apr_atomic_casptr(&m_ptr, NULL, get()));
+ }
+
+ /* Sets the wrapped pointer to PTR iff it is NULL, and returns the
+ old value. */
+ ClassImpl* test_and_set(ClassImpl* ptr)
+ {
+ return static_cast<ClassImpl*>(
+ apr_atomic_casptr(&m_ptr, ptr, NULL));
+ }
+
+ /* Returns the current value of the the wrapped pointer. */
+ ClassImpl* get() const
+ {
+ return static_cast<ClassImpl*>(
+ apr_atomic_casptr(&m_ptr, NULL, NULL));
+ }
+
+private:
+ // Non-copyable
+ ClassImplPtr(const ClassImplPtr&);
+ ClassImplPtr& operator=(const ClassImplPtr&);
+
+ mutable volatile void* m_ptr;
+};
+} // anonymous namespace
+
+
+namespace Java {
+
+class ClassCacheImpl
+{
+
+ friend class ClassCache;
+
+ // We only statically initialize a few of the common class wrappers.
+ explicit ClassCacheImpl(Env env) :
+
+#define JNIWRAPPER_INIT_CACHED_CLASS(M, C) \
+ m_impl_##M(new C::ClassImpl(env, env.FindClass(C::m_class_name)))
+
+ JNIWRAPPER_INIT_CACHED_CLASS(object, Object),
+ JNIWRAPPER_INIT_CACHED_CLASS(classtype, Class),
+ JNIWRAPPER_INIT_CACHED_CLASS(throwable, Exception),
+ JNIWRAPPER_INIT_CACHED_CLASS(string, String)
+#undef JNIWRAPPER_INIT_CACHED_CLASS
+ {}
+
+ // We can't do this in the constructor above, because the satic
+ // initializers will expect that ClassCache::m_impl is already set;
+ // that doesn't happen until the constructor returns.
+ void static_init(Env env)
+ {
+#define JNIWRAPPER_STATIC_CACHED_CLASS(M, C) \
+ C::static_init(env, m_impl_##M->get_class())
+
+ // No-op JNIWRAPPER_STATIC_CACHED_CLASS(object, Object);
+ JNIWRAPPER_STATIC_CACHED_CLASS(classtype, Class);
+ JNIWRAPPER_STATIC_CACHED_CLASS(throwable, Exception);
+ // No-op JNIWRAPPER_STATIC_CACHED_CLASS(string, String);
+#undef JNIWRAPPER_STATIC_CACHED_CLASS
+ }
+
+ // The statically initialized calss wrappers are always defined and
+ // therefore do not need atomic access.
+#define JNIWRAPPER_DEFINE_CACHED_CLASS(M, C) \
+ std::auto_ptr<Object::ClassImpl> m_impl_##M; \
+ const Object::ClassImpl* get_##M(Env) \
+ { \
+ return m_impl_##M.get(); \
+ }
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(object, Object)
+ JNIWRAPPER_DEFINE_CACHED_CLASS(classtype, Class)
+ JNIWRAPPER_DEFINE_CACHED_CLASS(throwable, Exception)
+ JNIWRAPPER_DEFINE_CACHED_CLASS(string, String)
+#undef JNIWRAPPER_DEFINE_CACHED_CLASS
+
+ // All other class wrappers must be atomically initialized
+#define JNIWRAPPER_DEFINE_CACHED_CLASS(M, C) \
+ ClassImplPtr m_impl_##M; \
+ const Object::ClassImpl* get_##M(Env env) \
+ { \
+ Object::ClassImpl* pimpl = m_impl_##M.get(); \
+ if (!pimpl) \
+ { \
+ std::auto_ptr<Object::ClassImpl> tmp( \
+ new C::ClassImpl( \
+ env, env.FindClass(C::m_class_name))); \
+ pimpl = m_impl_##M.test_and_set(tmp.get()); \
+ if (!pimpl) \
+ pimpl = tmp.release(); \
+ } \
+ return pimpl; \
+ }
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(exc_index_out_of_bounds,
+ IndexOutOfBoundsException);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(exc_no_such_element,
+ NoSuchElementException);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(iterator, BaseIterator);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(list, BaseImmutableList);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(array_list, BaseList);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(map, BaseImmutableMap);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(set, BaseImmutableMap::Set);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(map_entry, BaseImmutableMap::Entry);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(hash_map, BaseMap);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(input_stream, InputStream);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(output_stream, OutputStream);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(byte_buffer,
+ ByteChannel::ByteBuffer);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(subversion_exception,
+ ::JavaHL::SubversionException);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(authn_cb,
+ ::JavaHL::AuthnCallback);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(authn_result,
+ ::JavaHL::AuthnCallback::AuthnResult);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(authn_ssl_server_cert_failures,
+ ::JavaHL::AuthnCallback::SSLServerCertFailures);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(authn_ssl_server_cert_info,
+ ::JavaHL::AuthnCallback::SSLServerCertInfo);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(user_passwd_cb,
+ ::JavaHL::UserPasswordCallback);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(credential,
+ ::JavaHL::Credential);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(credential_kind,
+ ::JavaHL::Credential::Kind);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(external_item,
+ ::JavaHL::ExternalItem);
+
+ JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_base_cb,
+ ::JavaHL::ProvideBaseCallback);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_base_cb_ret,
+ ::JavaHL::ProvideBaseCallback::ReturnValue);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_props_cb,
+ ::JavaHL::ProvidePropsCallback);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(editor_provide_props_cb_ret,
+ ::JavaHL::ProvidePropsCallback::ReturnValue);
+ JNIWRAPPER_DEFINE_CACHED_CLASS(editor_get_kind_cb,
+ ::JavaHL::GetNodeKindCallback);
+#undef JNIWRAPPER_DEFINE_CACHED_CLASS
+};
+
+
+ClassCacheImpl* ClassCache::m_impl = NULL;
+
+void ClassCache::create()
+{
+ const char* exception_message = NULL;
+
+ try
+ {
+ const Env env;
+ m_impl = new ClassCacheImpl(env);
+ m_impl->static_init(env);
+ }
+ catch (const SignalExceptionThrown&)
+ {}
+ catch (const std::exception& ex)
+ {
+ exception_message = ex.what();
+ }
+ catch (...)
+ {
+ exception_message = "Caught unknown C++ exception";
+ }
+
+ // Do not throw any more exceptions from here, so use the raw environment.
+ ::JNIEnv* const jenv = Env().get();
+ if (exception_message || jenv->ExceptionCheck())
+ {
+ jobject cause = jenv->ExceptionOccurred();
+ if (cause)
+ jenv->ExceptionClear();
+
+ const jclass rtx = jenv->FindClass("java/lang/RuntimeException");
+ const jmethodID ctor = jenv->GetMethodID(rtx, "<init>",
+ "(Ljava/lang/String;"
+ "Ljava/lang/Throwable;)V");
+ if (!cause && exception_message)
+ {
+ const jstring msg = jenv->NewStringUTF(exception_message);
+ cause = jenv->NewObject(rtx, ctor, msg, jthrowable(0));
+ }
+ const jstring reason =
+ jenv->NewStringUTF("JavaHL native library initialization failed");
+ const jobject exception = jenv->NewObject(rtx, ctor, reason, cause);
+ jenv->Throw(jthrowable(exception));
+ }
+}
+
+void ClassCache::destroy()
+{
+ ClassCacheImpl* const pimpl = m_impl;
+ m_impl = NULL;
+ delete pimpl;
+}
+
+#define JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(M) \
+const Object::ClassImpl* ClassCache::get_##M(Env env) \
+{ \
+ return m_impl->get_##M(env); \
+}
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(object);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(classtype);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(throwable);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(string);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(exc_index_out_of_bounds);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(exc_no_such_element);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(list);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(array_list);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(map);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(set);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(iterator);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(map_entry);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(hash_map);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(input_stream);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(output_stream);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(byte_buffer);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(subversion_exception);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_cb);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_result);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_ssl_server_cert_failures);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(authn_ssl_server_cert_info);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(user_passwd_cb);
+
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(credential);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(credential_kind);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(external_item);
+
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_base_cb);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_base_cb_ret);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_props_cb);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_provide_props_cb_ret);
+JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR(editor_get_kind_cb);
+#undef JNIWRAPPER_IMPL_CLASS_CACHE_ACCESSOR
+
+} // namespace Java