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 * @file JNIUtil.h 24 * @brief Interface of the class JNIUtil 25 */ 26 27 #ifndef JNIUTIL_H 28 #define JNIUTIL_H 29 30 #include <list> 31 #include <vector> 32 #include "Pool.h" 33 struct apr_pool_t; 34 class JNIMutex; 35 class SVNBase; 36 #include <jni.h> 37 #include <fstream> 38 #include <apr_time.h> 39 #include <string> 40 #include <vector> 41 42 struct svn_error_t; 43 struct svn_string_t; 44 45 #include "svn_error.h" 46 47 48 /** 49 * The name of the package in which the JavaHL classes are defined. 50 */ 51 #define JAVAHL_PACKAGE "org/apache/subversion/javahl" 52 53 /** 54 * Construct a JavaHL class name for JNIEnv::FindClass. 55 */ 56 #define JAVAHL_CLASS(name) JAVAHL_PACKAGE name 57 58 /** 59 * Construct a JavaHL class parameter name for JNIEnv::GetMethodID & co. 60 */ 61 #define JAVAHL_ARG(name) "L" JAVAHL_PACKAGE name 62 63 64 /** 65 * Class to hold a number of JNI related utility methods. No Objects 66 * of this class are ever created. 67 */ 68 class JNIUtil 69 { 70 public: 71 static svn_error_t *preprocessPath(const char *&path, apr_pool_t *pool); 72 73 /** 74 * Throw the Java NativeException instance named by 75 * exceptionClassName. A NativeException sub-class must supply a 76 * 3-arg constructor identical to that of NativeException. @a 77 * source is any file name and line number information. 78 */ 79 static void throwNativeException(const char *exceptionClassName, 80 const char *msg, 81 const char *source = NULL, 82 int aprErr = -1); 83 84 static void throwNullPointerException(const char *message); 85 static jbyteArray makeJByteArray(const void *data, int length); 86 static jbyteArray makeJByteArray(const svn_string_t *str); 87 static jobject createDate(apr_time_t time); 88 static apr_time_t getDate(jobject jdate); 89 static void logMessage(const char *message); 90 static int getLogLevel(); 91 static void initLogFile(int level, jstring path); 92 static jstring makeJString(const char *txt); 93 static JNIEnv *getEnv(); 94 95 /** 96 * @return Whether any Throwable has been raised. 97 */ isExceptionThrown()98 static bool isExceptionThrown() { return isJavaExceptionThrown(); } isJavaExceptionThrown()99 static bool isJavaExceptionThrown() 100 { 101 return getEnv()->ExceptionCheck(); 102 } 103 104 static svn_error_t *wrapJavaException(); 105 static jthrowable unwrapJavaException(const svn_error_t *err); 106 107 static void handleAPRError(int error, const char *op); 108 109 /** 110 * Put @a object in the list of finalized objects queued up to be 111 * deleted (by another thread) during the next operation. 112 * 113 * @param object The C++ peer of the finalized (Java) object. 114 * @since 1.4.0 115 */ 116 static void enqueueForDeletion(SVNBase *object); 117 118 /** 119 * @deprecated Use the more appropriately named 120 * enqueueForDeletion() instead. 121 */ 122 static void putFinalizedClient(SVNBase *cl); 123 124 /** 125 * Convert any exception that may have been thrown into a textual 126 * representation. Return @c NULL if no exception has 127 * occurred. Useful for converting Java @c Exceptions into @c 128 * svn_error_t's. 129 */ 130 static const char *thrownExceptionToCString(SVN::Pool &in_pool); 131 132 /** 133 * Check if a Java exception was thrown and convert it to a 134 * Subversion error, using @a errorcode as the generic error code. 135 */ 136 static svn_error_t* checkJavaException(apr_status_t errorcode); 137 138 /** 139 * Create a Java exception corresponding to err, and run 140 * svn_error_clear() on err. 141 */ 142 static jthrowable createClientException(svn_error_t *err, 143 jthrowable jcause = NULL); 144 145 /** 146 * Throw a Java exception corresponding to err, and run 147 * svn_error_clear() on err. 148 */ 149 static void handleSVNError(svn_error_t *err, jthrowable jcause = NULL); 150 151 static std::string makeSVNErrorMessage(svn_error_t *err, 152 jstring *jerror_message, 153 jobject *jmessage_stack); 154 155 /** 156 * Create and throw a java.lang.Throwable instance. 157 * 158 * @param name The class name (in path form, with slashes in lieu 159 * of dots) of the Throwable to create and raise. 160 * @param message The message text of the Throwable. 161 */ 162 static void raiseThrowable(const char *name, const char *message); 163 164 /** 165 * Creates and throws a JNIError. 166 * 167 * @param message The message text of the JNIError. 168 */ throwError(const char * message)169 static void throwError(const char *message) 170 { 171 raiseThrowable(JAVAHL_CLASS("/JNIError"), message); 172 } 173 174 static apr_pool_t *getPool(); 175 static bool JNIInit(JNIEnv *env); 176 static bool initializeJNIRuntime(); 177 enum { noLog, errorLog, exceptionLog, entryLog } LogLevel; 178 179 /** 180 * Mutex that secures the global configuration object. 181 */ 182 static JNIMutex *g_configMutex; 183 184 private: 185 friend bool initialize_jni_util(JNIEnv *env); 186 static bool JNIGlobalInit(JNIEnv *env); 187 188 static jthrowable wrappedCreateClientException(svn_error_t *err, 189 jthrowable jcause); 190 static void putErrorsInTrace(svn_error_t *err, 191 std::vector<jobject> &stackTrace); 192 193 /** 194 * The log level of this module. 195 */ 196 static int g_logLevel; 197 198 /** 199 * Global master pool. All other pool are subpools of this pool. 200 */ 201 static apr_pool_t *g_pool; 202 203 /** 204 * List of objects finalized, where the C++ peer has not yet be 205 * deleted. 206 */ 207 static std::list<SVNBase*> g_finalizedObjects; 208 209 /** 210 * Mutex to secure the g_finalizedObjects list. 211 */ 212 static JNIMutex *g_finalizedObjectsMutex; 213 214 /** 215 * Mutex to secure the access to the log file. 216 */ 217 static JNIMutex *g_logMutex; 218 219 /** 220 * Flag, that an exception occurred during our initialization. 221 */ 222 static bool g_initException; 223 224 /** 225 * The stream to write log messages to. 226 */ 227 static std::ofstream g_logStream; 228 }; 229 230 /** 231 * A statement macro used for checking NULL pointers, in the style of 232 * SVN_ERR(). 233 * 234 * Evaluate @a expr. If it equals NULL, throw an NullPointerException with 235 * the value @a str, and return the @a ret_val. Otherwise, continue. 236 * 237 * Note that if the enclosing function returns <tt>void</tt>, @a ret_val may 238 * be blank. 239 */ 240 241 #define SVN_JNI_NULL_PTR_EX(expr, str, ret_val) \ 242 if ((expr) == NULL) { \ 243 JNIUtil::throwNullPointerException(str); \ 244 return ret_val; \ 245 } 246 247 /** 248 * A statement macro used for checking for errors, in the style of 249 * SVN_ERR(). 250 * 251 * Evalute @a expr. If it yields an error, handle the JNI error, and 252 * return @a ret_val. Otherwise, continue. 253 * 254 * Note that if the enclosing function returns <tt>void</tt>, @a ret_val may 255 * be blank. 256 */ 257 258 #define SVN_JNI_ERR(expr, ret_val) \ 259 do { \ 260 svn_error_t *svn_jni_err__temp = (expr); \ 261 if (svn_jni_err__temp != SVN_NO_ERROR) { \ 262 JNIUtil::handleSVNError(svn_jni_err__temp); \ 263 return ret_val; \ 264 } \ 265 } while (0) 266 267 /** 268 * The initial capacity of a create local reference frame. 269 */ 270 #define LOCAL_FRAME_SIZE 16 271 272 /** 273 * A statement macro use to pop the reference frame and return NULL 274 */ 275 #define POP_AND_RETURN(ret_val) \ 276 do \ 277 { \ 278 env->PopLocalFrame(NULL); \ 279 return ret_val; \ 280 } \ 281 while (0) 282 283 /** 284 * A statement macro use to pop the reference frame and return 285 */ 286 #define POP_AND_RETURN_NOTHING() \ 287 do \ 288 { \ 289 env->PopLocalFrame(NULL); \ 290 return; \ 291 } \ 292 while (0) 293 294 #define POP_AND_RETURN_EXCEPTION_AS_SVNERROR() \ 295 do \ 296 { \ 297 svn_error_t *svn__err_for_exception = JNIUtil::wrapJavaException(); \ 298 \ 299 env->PopLocalFrame(NULL); \ 300 return svn__err_for_exception; \ 301 } \ 302 while (0) 303 304 305 /** 306 * A useful macro. 307 */ 308 #define POP_AND_RETURN_NULL POP_AND_RETURN(NULL) 309 310 #define CPPADDR_NULL_PTR(expr, ret_val) \ 311 do { \ 312 if ((expr) == NULL) { \ 313 JNIUtil::throwError(_("bad C++ this")); \ 314 return ret_val; \ 315 } \ 316 } while (0) 317 318 #define SVN_JNI_CATCH(statement, errorcode) \ 319 do { \ 320 do { statement; } while(0); \ 321 SVN_ERR(JNIUtil::checkJavaException((errorcode))); \ 322 } while(0) 323 324 #define SVN_JNI_CATCH_VOID(statement) \ 325 do { \ 326 do { statement; } while(0); \ 327 if (JNIUtil::getEnv()->ExceptionCheck()) { \ 328 JNIUtil::getEnv()->ExceptionClear(); \ 329 return; \ 330 } \ 331 } while(0) 332 333 /** 334 * If there's an exception pending, temporarily stash it away, then 335 * re-throw again in destructor. The goal is to allow some Java calls 336 * to be made despite a pending exception. For example, doing some 337 * necessary cleanup. 338 */ 339 class StashException 340 { 341 public: 342 /* 343 * Works like stashException(). 344 */ 345 StashException(JNIEnv* env); 346 347 /** 348 * If there's an exception stashed, re-throws it. 349 */ 350 ~StashException(); 351 352 /** 353 * Check for a pending exception. 354 * If present, stash it away until this class's destructor. 355 * If another exception is already stashed, forget the _new_ one. The 356 * reason behind it is that usually the first exception is the most 357 * informative. 358 */ 359 void stashException(); 360 361 private: 362 JNIEnv* m_env; 363 jthrowable m_stashed; 364 }; 365 366 #endif // JNIUTIL_H 367