1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "JavaTypes.h"
  27 #include "PlatformString.h"
  28 
  29 #include <list>
  30 
  31 
  32 #ifdef DEBUG
  33 TString JavaException::CreateExceptionMessage(JNIEnv* Env,
  34         jthrowable Exception, jmethodID GetCauseMethod,
  35         jmethodID GetStackTraceMethod, jmethodID ThrowableToTStringMethod,
  36         jmethodID FrameToTStringMethod) {
  37 
  38     TString result;
  39     jobjectArray frames =
  40             (jobjectArray)Env->CallObjectMethod(Exception, GetStackTraceMethod);
  41 
  42     // Append Throwable.toTString().
  43     if (0 != frames) {
  44         jstring jstr = (jstring)Env->CallObjectMethod(Exception,
  45                 ThrowableToTStringMethod);
  46         const char* str = Env->GetStringUTFChars(jstr, 0);
  47         result += PlatformString(str).toPlatformString();
  48         Env->ReleaseStringUTFChars(jstr, str);
  49         Env->DeleteLocalRef(jstr);
  50     }
  51 
  52     // Append stack trace if one exists.
  53     if (Env->GetArrayLength(frames) > 0) {
  54         jsize i = 0;
  55 
  56         for (i = 0; i < Env->GetArrayLength(frames); i++) {
  57             // Get the string from the next frame and append it to
  58             // the error message.
  59             jobject frame = Env->GetObjectArrayElement(frames, i);
  60             jstring obj = (jstring)Env->CallObjectMethod(frame,
  61                     FrameToTStringMethod);
  62             const char* str = Env->GetStringUTFChars(obj, 0);
  63             result += _T("\n  ");
  64             result += PlatformString(str).toPlatformString();
  65             Env->ReleaseStringUTFChars(obj, str);
  66             Env->DeleteLocalRef(obj);
  67             Env->DeleteLocalRef(frame);
  68         }
  69     }
  70 
  71     // If Exception has a cause then append the stack trace messages.
  72     if (0 != frames) {
  73         jthrowable cause =
  74                 (jthrowable)Env->CallObjectMethod(Exception, GetCauseMethod);
  75 
  76         if (cause != NULL) {
  77             result += CreateExceptionMessage(Env, cause, GetCauseMethod,
  78                 GetStackTraceMethod, ThrowableToTStringMethod,
  79                 FrameToTStringMethod);
  80         }
  81     }
  82 
  83     return result;
  84 }
  85 #endif //DEBUG
  86 
  87 JavaException::JavaException() : Exception() {}
  88 
  89 //#ifdef WINDOWS
  90 JavaException::JavaException(JNIEnv *Env,
  91         const TString Message) : Exception(Message) {
  92 //#endif //WINDOWS
  93 //#ifdef POSIX
  94 //JavaException::JavaException(JNIEnv *Env, TString message) {
  95 //#endif //POSIX
  96 
  97     FEnv = Env;
  98     FException = Env->ExceptionOccurred();
  99     Env->ExceptionClear();
 100 
 101 #ifdef DEBUG
 102     Platform& platform = Platform::GetInstance();
 103 
 104     if (platform.GetDebugState() == dsNone) {
 105         jclass ThrowableClass = Env->FindClass("java/lang/Throwable");
 106 
 107         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 108             Env->ExceptionClear();
 109             return;
 110         }
 111 
 112         jmethodID GetCauseMethod = Env->GetMethodID(ThrowableClass,
 113                 "getCause", "()Ljava/lang/Throwable;");
 114 
 115         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 116             Env->ExceptionClear();
 117             return;
 118         }
 119 
 120         jmethodID GetStackTraceMethod = Env->GetMethodID(ThrowableClass,
 121                  "getStackTrace", "()[Ljava/lang/StackTraceElement;");
 122 
 123         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 124             Env->ExceptionClear();
 125             return;
 126         }
 127 
 128         jmethodID ThrowableToTStringMethod = Env->GetMethodID(ThrowableClass,
 129                 "toString", "()Ljava/lang/String;");
 130 
 131         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 132             Env->ExceptionClear();
 133             return;
 134         }
 135 
 136         jclass FrameClass = Env->FindClass("java/lang/StackTraceElement");
 137 
 138         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 139             Env->ExceptionClear();
 140             return;
 141         }
 142 
 143         jmethodID FrameToTStringMethod = Env->GetMethodID(FrameClass,
 144                 "toString", "()Ljava/lang/String;");
 145 
 146         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 147             Env->ExceptionClear();
 148             return;
 149         }
 150 
 151         TString lmessage = CreateExceptionMessage(Env, FException,
 152                 GetCauseMethod, GetStackTraceMethod, ThrowableToTStringMethod,
 153                 FrameToTStringMethod);
 154         SetMessage(lmessage);
 155     }
 156 #endif //DEBUG
 157 }
 158 
 159 void JavaException::Rethrow() {
 160     FEnv->Throw(FException);
 161 }
 162 
 163 //----------------------------------------------------------------------------
 164 
 165 JavaStaticMethod::JavaStaticMethod(JNIEnv *Env, jclass Class, jmethodID Method) {
 166     FEnv = Env;
 167     FClass = Class;
 168     FMethod = Method;
 169 }
 170 
 171 void JavaStaticMethod::CallVoidMethod(int Count, ...) {
 172     va_list args;
 173     va_start(args, Count);
 174     FEnv->CallStaticVoidMethodV(FClass, FMethod, args);
 175     va_end(args);
 176 
 177     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 178         Messages& messages = Messages::GetInstance();
 179         throw JavaException(FEnv, messages.GetMessage(ERROR_INVOKING_METHOD));
 180     }
 181 }
 182 
 183 JavaStaticMethod::operator jmethodID () {
 184     return FMethod;
 185 }
 186 
 187 //----------------------------------------------------------------------------
 188 
 189 JavaMethod::JavaMethod(JNIEnv *Env, jobject Obj, jmethodID Method) {
 190     FEnv = Env;
 191     FObj = Obj;
 192     FMethod = Method;
 193 }
 194 
 195 void JavaMethod::CallVoidMethod(int Count, ...) {
 196     va_list args;
 197     va_start(args, Count);
 198     FEnv->CallVoidMethodV(FObj, FMethod, args);
 199     va_end(args);
 200 
 201     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 202         Messages& messages = Messages::GetInstance();
 203         throw JavaException(FEnv, messages.GetMessage(ERROR_INVOKING_METHOD));
 204     }
 205 }
 206 
 207 JavaMethod::operator jmethodID () {
 208     return FMethod;
 209 }
 210 
 211 //----------------------------------------------------------------------------
 212 
 213 JavaClass::JavaClass(JNIEnv *Env, TString Name) {
 214     FEnv = Env;
 215     FClassName = Name;
 216     FClass = FEnv->FindClass(PlatformString(FClassName));
 217 
 218     if (FClass == NULL || FEnv->ExceptionCheck() == JNI_TRUE) {
 219         Messages& messages = Messages::GetInstance();
 220         TString message = messages.GetMessage(CLASS_NOT_FOUND);
 221         message = PlatformString::Format(message, FClassName.data());
 222         throw JavaException(FEnv, message);
 223     }
 224 }
 225 
 226 JavaClass::~JavaClass() {
 227     FEnv->DeleteLocalRef(FClass);
 228 }
 229 
 230 JavaStaticMethod JavaClass::GetStaticMethod(TString Name, TString Signature) {
 231     jmethodID method = FEnv->GetStaticMethodID(FClass, PlatformString(Name),
 232             PlatformString(Signature));
 233 
 234     if (method == NULL || FEnv->ExceptionCheck() == JNI_TRUE) {
 235         Messages& messages = Messages::GetInstance();
 236         TString message = messages.GetMessage(METHOD_NOT_FOUND);
 237         message = PlatformString::Format(message, Name.data(),
 238                 FClassName.data());
 239         throw JavaException(FEnv, message);
 240     }
 241 
 242     return JavaStaticMethod(FEnv, FClass, method);
 243 }
 244 
 245 JavaClass::operator jclass () {
 246     return FClass;
 247 }
 248 
 249 //----------------------------------------------------------------------------
 250 
 251 void JavaStringArray::Initialize(size_t Size) {
 252     JavaClass jstringClass(FEnv, _T("java/lang/String"));
 253 
 254     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 255         Messages& messages = Messages::GetInstance();
 256         TString message = messages.GetMessage(CLASS_NOT_FOUND);
 257         message = PlatformString::Format(message, _T("String"));
 258         throw JavaException(FEnv, message.data());
 259     }
 260 
 261     jstring str = PlatformString("").toJString(FEnv);
 262     FData = (jobjectArray)FEnv->NewObjectArray((jsize)Size, jstringClass, str);
 263 
 264     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 265         throw JavaException(FEnv, _T("Error"));
 266     }
 267 }
 268 
 269 JavaStringArray::JavaStringArray(JNIEnv *Env, size_t Size) {
 270     FEnv = Env;
 271     Initialize(Size);
 272 }
 273 
 274 JavaStringArray::JavaStringArray(JNIEnv *Env, jobjectArray Data) {
 275     FEnv = Env;
 276     FData = Data;
 277 }
 278 
 279 JavaStringArray::JavaStringArray(JNIEnv *Env, std::list<TString> Items) {
 280     FEnv = Env;
 281     Initialize(Items.size());
 282     unsigned int index = 0;
 283 
 284     for (std::list<TString>::const_iterator iterator = Items.begin();
 285             iterator != Items.end(); iterator++) {
 286         TString item = *iterator;
 287         SetValue(index, PlatformString(item).toJString(FEnv));
 288         index++;
 289     }
 290 }
 291 
 292 jobjectArray JavaStringArray::GetData() {
 293     return FData;
 294 }
 295 
 296 void JavaStringArray::SetValue(jsize Index, jstring Item) {
 297     FEnv->SetObjectArrayElement(FData, Index, Item);
 298 
 299     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 300         throw JavaException(FEnv, _T("Error"));
 301     }
 302 }
 303 
 304 jstring JavaStringArray::GetValue(jsize Index) {
 305     jstring result = (jstring)FEnv->GetObjectArrayElement(FData, Index);
 306 
 307     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 308         throw JavaException(FEnv, _T("Error"));
 309     }
 310 
 311     return result;
 312 }
 313 
 314 unsigned int JavaStringArray::Count() {
 315     unsigned int result = FEnv->GetArrayLength(FData);
 316 
 317     if (FEnv->ExceptionCheck() == JNI_TRUE) {
 318         throw JavaException(FEnv, _T("Error"));
 319     }
 320 
 321     return result;
 322 }