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 #ifndef SVN_JAVAHL_JNIWRAPPER_STACK_HPP
25 #define SVN_JAVAHL_JNIWRAPPER_STACK_HPP
26 
27 #ifdef SVN_JAVAHL_DEBUG
28 #  ifndef SVN_JAVAHL_ASSERT_EXCEPTION_THROWN
29 #    include <cassert>
30 #    define SVN_JAVAHL_ASSERT_EXCEPTION_THROWN(E) \
31        assert((E).ExceptionCheck())
32 #  endif // SVN_JAVAHL_ASSERT_EXCEPTION_THROWN
33 #else
34 #  define SVN_JAVAHL_ASSERT_EXCEPTION_THROWN(E)
35 # endif // SVN_JAVAHL_DEBUG
36 
37 #include "../JNIStackElement.h"
38 #include "jni_env.hpp"
39 #include "jni_exception.hpp"
40 
41 #include "svn_error.h"
42 
43 /**
44  * Boilerplate for the native method implementation entry point.
45  *
46  * Every native method implementation should start by invoking this
47  * macro to initialize the logging stack element and begin the
48  * try/catch block of the function body.
49  *
50  * @param C The name of the Java class that declares this method.
51  * @param M The (Java) name of the method.
52  *
53  * This macro expects two additional parameters to be available
54  * (either as function arguments or local variables):
55  * @c JNIEnv* @a jenv and @c jobject @a jthis.
56  *
57  * @since New in 1.9.
58  */
59 #define SVN_JAVAHL_JNI_TRY(C, M)                                \
60   ::JNIStackElement st_ac_ke_le_me_nt_(jenv, #C, #M, jthis);    \
61   try
62 
63 /**
64  * Boilerplate for the native method implementation entry point.
65  *
66  * Initializes local variable named @a V as a pointer to an instance
67  * of the native-bound class @a C.
68  *
69  * @since New in 1.9.
70  */
71 #define SVN_JAVAHL_GET_BOUND_OBJECT(C, V)               \
72   C* const V = C::get_self(::Java::Env(jenv), jthis)
73 
74 /**
75  * Boilerplate for the native method implementation entry point.
76  *
77  * Like #SVN_JAVAHL_JNI_TRY, but for static methods where the @c jthis
78  * argument is not available.
79  *
80  * This macro expects two additional parameters to be available
81  * (either as function arguments or local variables):
82  * @c JNIEnv* @a jenv and @c jclass @a jclazz.
83  *
84  * @since New in 1.9.
85  */
86 #define SVN_JAVAHL_JNI_TRY_STATIC(C, M)                         \
87   ::JNIStackElement st_ac_ke_le_me_nt_(jenv, #C, #M, jclazz);   \
88   try
89 
90 
91 /**
92  * Boilerplate for the native method implementation exit point.
93  *
94  * Every native method implementation should end by invoking this
95  * macro to close the try/catch block of the function body and handle
96  * any exceptions thrown by the method implementation.
97  *
98  * This boilerplate variant converts C++ exceptions to the Java
99  * exception type @a X, but retains exceptions that are already in
100  * progress.
101  *
102  * @since New in 1.9.
103  */
104 #define SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(X)                            \
105   catch (const ::Java::SignalExceptionThrown&)                          \
106     {                                                                   \
107       SVN_JAVAHL_ASSERT_EXCEPTION_THROWN(::Java::Env(jenv));            \
108     }                                                                   \
109   catch (const ::std::exception& ex)                                    \
110     {                                                                   \
111       X(::Java::Env(jenv)).throw_java_exception(ex.what());             \
112     }                                                                   \
113   catch (...)                                                           \
114     {                                                                   \
115       const char* const msg = Java::unknown_cxx_exception_message();    \
116       X(::Java::Env(jenv)).throw_java_exception(msg);                   \
117     }
118 
119 /**
120  * Boilerplate for the native method implementation exit point.
121  *
122  * Invokes #SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION to throw a
123  * @c RuntimeException.
124  *
125  * @since New in 1.9.
126  */
127 #define SVN_JAVAHL_JNI_CATCH                                            \
128   SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(::Java::RuntimeException)
129 
130 /**
131  * Invocation wrapper for functions that return an @c svn_error_t *.
132  *
133  * @param E A wrapped environment (@c Java::Env) instance.
134  * @param S The statement to execute in the checked context.
135  *
136  * @since New in 1.9.
137  */
138 #define SVN_JAVAHL_CHECK(E, S)                                          \
139   do {                                                                  \
140     svn_error_t* const ja_va_hl_err_te_mp_ = (S);                       \
141     if (ja_va_hl_err_te_mp_)                                            \
142       ::Java::handle_svn_error((E), ja_va_hl_err_te_mp_);               \
143   } while(0)
144 
145 /**
146  * Invocation wrapper for calling Java methods that may throw an
147  * exception from within a native callback that is expected to return
148  * an @c svn_error_t*.
149  *
150  * @param E A wrapped environment (@c Java::Env) instance.
151  * @param C A Subversion or APR error code.
152  * @param S The statement to execute in the checked context.
153  *
154  * @since New in 1.9.
155  */
156 #define SVN_JAVAHL_CATCH(E, C, S)                                       \
157   try                                                                   \
158     {                                                                   \
159       S;                                                                \
160     }                                                                   \
161   catch (const ::Java::SignalExceptionThrown&)                          \
162     {                                                                   \
163       SVN_JAVAHL_ASSERT_EXCEPTION_THROWN((E));                          \
164       return Java::caught_java_exception_error((C));                    \
165     }                                                                   \
166   catch (const ::std::exception& ex)                                    \
167     {                                                                   \
168       const char* const msg = ex.what();                                \
169       ::Java::RuntimeException((E)).throw_java_exception(msg);          \
170       return svn_error_create((C), NULL, msg);                          \
171     }                                                                   \
172   catch (...)                                                           \
173     {                                                                   \
174       const char* const msg = Java::unknown_cxx_exception_message();    \
175       ::Java::RuntimeException((E)).throw_java_exception(msg);          \
176       return svn_error_create((C), NULL, msg);                          \
177     }
178 
179 /**
180  * Exception checker for the oldstyle implementation that does not use
181  * the @c Java::Env environment wrapper.
182  *
183  * @param E A wrapped environment (@c Java::Env) instance.
184  *
185  * @since New in 1.9.
186  */
187 #define SVN_JAVAHL_OLDSTYLE_EXCEPTION_CHECK(E)  \
188   do {                                          \
189     if ((E).ExceptionCheck())                   \
190       throw ::Java::SignalExceptionThrown();    \
191   } while(0)
192 
193 
194 namespace Java {
195 
196 /**
197  * Handle an error @a err returned from a native function and throws
198  * an appropriate Java exception.
199  *
200  * @since New in 1.9.
201  */
202 void handle_svn_error(Env env, svn_error_t* err);
203 
204 /**
205  * Return a localized error string for an unknown C++ exception.
206  *
207  * @since New in 1.9.
208  */
209 const char* unknown_cxx_exception_message() throw();
210 
211 /**
212  * Create an svn_error_t for a caught Java exception.
213  *
214  * @since New in 1.9.
215  */
216 svn_error_t* caught_java_exception_error(apr_status_t status) throw();
217 
218 } // namespace Java
219 
220 #endif // SVN_JAVAHL_JNIWRAPPER_STACK_HPP
221