/************ Javaconn C++ Functions Source Code File (.CPP) ***********/
/* Name: JAVAConn.CPP Version 1.1 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
/* */
/* This file contains the JAVA connection classes functions. */
/***********************************************************************/
#if defined (_WIN32)
// This is needed for RegGetValue
#define _WINVER 0 x0601
#undef _WIN32_WINNT
#define _WIN32_WINNT 0 x0601
#endif // _WIN32
/***********************************************************************/
/* Include relevant MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
//#include <m_string.h>
#if defined (_WIN32)
#include <direct.h> // for getcwd
#if defined (__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
#else // !_WIN32
#if defined (UNIX)
#include <errno.h>
#else // !UNIX
#endif // !UNIX
#include <stdio.h>
#include <stdlib.h> // for getenv
#define NODW
#endif // !_WIN32
#include <m_string.h>
/***********************************************************************/
/* Required objects includes. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "colblk.h"
#include "xobject.h"
#include "xtable.h"
#include "tabext.h"
#include "javaconn.h"
#include "resource.h"
#include "valblk.h"
#include "osutil.h"
#if defined (_WIN32)
extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // _WIN32
#define nullptr 0
//TYPCONV GetTypeConv();
//int GetConvSize();
extern char *JvmPath; // The connect_jvm_path global variable value
extern char *ClassPath; // The connect_class_path global variable value
char *GetPluginDir(void );
char *GetMessageDir(void );
char *GetJavaWrapper(void ); // The connect_java_wrapper variable value
extern MYSQL_PLUGIN_IMPORT char lc_messages_dir[FN_REFLEN];
/***********************************************************************/
/* Static JAVAConn objects. */
/***********************************************************************/
void *JAVAConn::LibJvm = NULL;
CRTJVM JAVAConn::CreateJavaVM = NULL;
GETJVM JAVAConn::GetCreatedJavaVMs = NULL;
#if defined (_DEBUG)
GETDEF JAVAConn::GetDefaultJavaVMInitArgs = NULL;
#endif // _DEBUG
/***********************************************************************/
/* Some macro's (should be defined elsewhere to be more accessible) */
/***********************************************************************/
#if defined (_DEBUG)
#define ASSERT(f) assert(f)
#define DEBUG_ONLY(f) (f)
#else // !_DEBUG
#define ASSERT(f) ((void )0 )
#define DEBUG_ONLY(f) ((void )0 )
#endif // !_DEBUG
/***********************************************************************/
/* JAVAConn construction/destruction. */
/***********************************************************************/
JAVAConn::JAVAConn(PGLOBAL g, PCSZ wrapper)
{
m_G = g;
jvm = nullptr; // Pointer to the JVM (Java Virtual Machine)
env = nullptr; // Pointer to native interface
jdi = nullptr; // Pointer to the java wrapper class
job = nullptr; // The java wrapper class object
errid = nullptr;
DiscFunc = "Disconnect" ;
Msg = NULL;
m_Wrap = (wrapper) ? wrapper : GetJavaWrapper();
if (!strchr(m_Wrap, '/' )) {
// Add the wrapper package name
char *wn = (char *)PlugSubAlloc(g, NULL, strlen(m_Wrap) + 10 );
m_Wrap = strcat(strcpy(wn, "wrappers/" ), m_Wrap);
} // endif m_Wrap
fp = NULL;
m_Opened = false ;
m_Connected = false ;
m_Rows = 0 ;
//*m_ErrMsg = '\0';
} // end of JAVAConn
//JAVAConn::~JAVAConn()
// {
//if (Connected())
// EndCom();
// } // end of ~JAVAConn
char *JAVAConn::GetUTFString(jstring s)
{
char *str;
const char *utf = env->GetStringUTFChars(s, nullptr);
str = PlugDup(m_G, utf);
env->ReleaseStringUTFChars(s, utf);
env->DeleteLocalRef(s);
return str;
} // end of GetUTFString
/***********************************************************************/
/* Screen for errors. */
/***********************************************************************/
bool JAVAConn::Check(jint rc)
{
jstring s;
if (env->ExceptionCheck()) {
jthrowable exc = env->ExceptionOccurred();
jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object" ),
"toString" , "()Ljava/lang/String;" );
if (exc != nullptr && tid != nullptr) {
s = (jstring)env->CallObjectMethod(exc, tid);
Msg = GetUTFString(s);
} else
Msg = "Exception occurred" ;
env->ExceptionClear();
} else if (rc < 0 ) {
s = (jstring)env->CallObjectMethod(job, errid);
Msg = GetUTFString(s);
} else
Msg = NULL;
return (Msg != NULL);
} // end of Check
/***********************************************************************/
/* Get MethodID if not exists yet. */
/***********************************************************************/
bool JAVAConn::gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig)
{
if (mid == nullptr) {
mid = env->GetMethodID(jdi, name, sig);
if (Check()) {
snprintf(g->Message, sizeof (g->Message), "%s" , Msg);
return true ;
} else
return false ;
} else
return false ;
} // end of gmID
#if 0
/***********************************************************************/
/* Utility routine. */
/***********************************************************************/
int JAVAConn::GetMaxValue(int n)
{
jint m;
jmethodID maxid = nullptr;
if (gmID(m_G, maxid, "GetMaxValue" , "(I)I" ))
return -1 ;
// call method
if (Check(m = env->CallIntMethod(job, maxid, n)))
htrc("GetMaxValue: %s" , Msg);
return (int )m;
} // end of GetMaxValue
#endif // 0
/***********************************************************************/
/* Reset the JVM library. */
/***********************************************************************/
void JAVAConn::ResetJVM(void )
{
if (LibJvm) {
#if defined (_WIN32)
FreeLibrary((HMODULE)LibJvm);
#else // !_WIN32
dlclose(LibJvm);
#endif // !_WIN32
LibJvm = NULL;
CreateJavaVM = NULL;
GetCreatedJavaVMs = NULL;
#if defined (_DEBUG)
GetDefaultJavaVMInitArgs = NULL;
#endif // _DEBUG
} // endif LibJvm
} // end of ResetJVM
/***********************************************************************/
/* Dynamically link the JVM library. */
/* The purpose of this function is to allow using the CONNECT plugin */
/* for other table types when the Java JDK is not installed. */
/***********************************************************************/
bool JAVAConn::GetJVM(PGLOBAL g)
{
int ntry;
if (!LibJvm) {
char soname[512 ];
#if defined (_WIN32)
for (ntry = 0 ; !LibJvm && ntry < 3 ; ntry++) {
if (!ntry && JvmPath) {
snprintf(soname, sizeof (soname), "%s\\jvm.dll" , JvmPath);
ntry = 3 ; // No other try
} else if (ntry < 2 && getenv("JAVA_HOME" )) {
safe_strcpy(soname, sizeof (soname), getenv("JAVA_HOME" ));
if (ntry == 1 )
safe_strcat(soname, sizeof (soname), "\\jre" );
safe_strcat(soname, sizeof (soname), "\\bin\\client\\jvm.dll" );
} else {
// Try to find it through the registry
char version[16 ];
char javaKey[64 ] = "SOFTWARE\\JavaSoft\\Java Runtime Environment" ;
LONG rc;
DWORD BufferSize = 16 ;
safe_strcpy(soname, sizeof (soname), "jvm.dll" ); // In case it fails
if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion" ,
RRF_RT_ANY, NULL, (PVOID)&version, &BufferSize)) == ERROR_SUCCESS) {
safe_strcat(javaKey, sizeof (javaKey), "\\" );
safe_strcat(javaKey, sizeof (javaKey), version);
BufferSize = sizeof (soname);
if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "RuntimeLib" ,
RRF_RT_ANY, NULL, (PVOID)&soname, &BufferSize)) != ERROR_SUCCESS)
printf("RegGetValue: rc=%ld\n" , rc);
} // endif rc
ntry = 3 ; // Try this only once
} // endelse
// Load the desired shared library
LibJvm = LoadLibrary(soname);
} // endfor ntry
// Get the needed entries
if (!LibJvm) {
char buf[256 ];
DWORD rc = GetLastError();
FormatMessage(FORMAT_MESSAGE_FLAGS, NULL, rc, 0 ,
(LPTSTR)buf, sizeof (buf), NULL);
snprintf(g->Message, sizeof (g->Message), MSG(DLL_LOAD_ERROR)": %s" , rc,
soname, buf);
} else if (!(CreateJavaVM = (CRTJVM)GetProcAddress((HINSTANCE)LibJvm,
"JNI_CreateJavaVM" ))) {
snprintf(g->Message, sizeof (g->Message), MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM" );
FreeLibrary((HMODULE)LibJvm);
LibJvm = NULL;
} else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm,
"JNI_GetCreatedJavaVMs" ))) {
snprintf(g->Message, sizeof (g->Message), MSG(PROCADD_ERROR), GetLastError(), "JNI_GetCreatedJavaVMs" );
FreeLibrary((HMODULE)LibJvm);
LibJvm = NULL;
#if defined (_DEBUG)
} else if (!(GetDefaultJavaVMInitArgs = (GETDEF)GetProcAddress((HINSTANCE)LibJvm,
"JNI_GetDefaultJavaVMInitArgs" ))) {
snprintf(g->Message, sizeof (g->Message), MSG(PROCADD_ERROR), GetLastError(),
"JNI_GetDefaultJavaVMInitArgs" );
FreeLibrary((HMODULE)LibJvm);
LibJvm = NULL;
#endif // _DEBUG
} // endif LibJvm
#else // !_WIN32
const char *error = NULL;
for (ntry = 0 ; !LibJvm && ntry < 2 ; ntry++) {
if (!ntry && JvmPath) {
snprintf(soname, sizeof (soname), "%s/libjvm.so" , JvmPath);
ntry = 2 ;
} else if (!ntry && getenv("JAVA_HOME" )) {
// TODO: Replace i386 by a better guess
snprintf(soname, sizeof (soname), "%s/jre/lib/i386/client/libjvm.so" ,
getenv("JAVA_HOME" ));
} else { // Will need LD_LIBRARY_PATH to be set
safe_strcpy(soname, sizeof (soname), "libjvm.so" );
ntry = 2 ;
} // endelse
LibJvm = dlopen(soname, RTLD_LAZY);
} // endfor ntry
// Load the desired shared library
if (!LibJvm) {
error = dlerror();
snprintf(g->Message, sizeof (g->Message), MSG(SHARED_LIB_ERR), soname, SVP(error));
} else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM" ))) {
error = dlerror();
snprintf(g->Message, sizeof (g->Message), MSG(GET_FUNC_ERR), "JNI_CreateJavaVM" , SVP(error));
dlclose(LibJvm);
LibJvm = NULL;
} else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs" ))) {
error = dlerror();
snprintf(g->Message, sizeof (g->Message), MSG(GET_FUNC_ERR), "JNI_GetCreatedJavaVMs" , SVP(error));
dlclose(LibJvm);
LibJvm = NULL;
#if defined (_DEBUG)
} else if (!(GetDefaultJavaVMInitArgs = (GETDEF)dlsym(LibJvm,
"JNI_GetDefaultJavaVMInitArgs" ))) {
error = dlerror();
snprintf(g->Message, sizeof (g->Message), MSG(GET_FUNC_ERR), "JNI_GetDefaultJavaVMInitArgs" , SVP(error));
dlclose(LibJvm);
LibJvm = NULL;
#endif // _DEBUG
} // endif LibJvm
#endif // !_WIN32
} // endif LibJvm
return LibJvm == NULL;
} // end of GetJVM
/***********************************************************************/
/* Open: connect to a data source. */
/***********************************************************************/
bool JAVAConn::Open(PGLOBAL g)
{
bool brc = true ;
jboolean jt = (trace(1 ));
// Link or check whether jvm library was linked
if (GetJVM(g))
return true ;
// Firstly check whether the jvm was already created
JavaVM* jvms[1 ];
jsize jsz;
jint rc = GetCreatedJavaVMs(jvms, 1 , &jsz);
if (rc == JNI_OK && jsz == 1 ) {
// jvm already existing
jvm = jvms[0 ];
rc = jvm->AttachCurrentThread((void **)&env, nullptr);
if (rc != JNI_OK) {
snprintf(g->Message, sizeof (g->Message), "Cannot attach jvm to the current thread" );
return true ;
} // endif rc
} else {
/*******************************************************************/
/* Create a new jvm */
/*******************************************************************/
PSTRG jpop = new (g)STRING(g, 512 , "-Djava.class.path=." );
char *cp = NULL;
char sep;
#if defined (_WIN32)
sep = ';' ;
#define N 1
//#define N 2
//#define N 3
#else
sep = ':' ;
#define N 1
#endif
// Add wrappers jar files
AddJars(jpop, sep);
//================== prepare loading of Java VM ============================
JavaVMInitArgs vm_args; // Initialization arguments
JavaVMOption* options = new JavaVMOption[N]; // JVM invocation options
// where to find java .class
if (ClassPath && *ClassPath) {
jpop->Append(sep);
jpop->Append(ClassPath);
} // endif ClassPath
jpop->Append(sep);
jpop->Append(GetMessageDir());
jpop->Append("JdbcInterface.jar" );
#if defined (MONGO_SUPPORT)
jpop->Append(sep);
jpop->Append(GetMessageDir());
jpop->Append("Mongo3.jar" );
jpop->Append(sep);
jpop->Append(GetMessageDir());
jpop->Append("Mongo2.jar" );
#endif // MONGO_SUPPORT
if ((cp = getenv("CLASSPATH" ))) {
jpop->Append(sep);
jpop->Append(cp);
} // endif cp
if (trace(1 )) {
htrc("ClassPath=%s\n" , ClassPath ? ClassPath : "null" );
htrc("CLASSPATH=%s\n" , cp ? cp : "null" );
htrc("%s\n" , jpop->GetStr());
} // endif trace
options[0 ].optionString = jpop->GetStr();
#if N == 2
options[1 ].optionString = "-Xcheck:jni" ;
#endif
#if N == 3
options[1 ].optionString = "-Xms256M" ;
options[2 ].optionString = "-Xmx512M" ;
#endif
#if defined (_DEBUG)
vm_args.version = JNI_VERSION_1_2; // minimum Java version
rc = GetDefaultJavaVMInitArgs(&vm_args);
#else
vm_args.version = JNI_VERSION_1_6; // minimum Java version
#endif // _DEBUG
vm_args.nOptions = N; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false ; // invalid options make the JVM init fail
//=============== load and initialize Java VM and JNI interface =============
rc = CreateJavaVM(&jvm, (void **)&env, &vm_args); // YES !!
delete [] options; // we then no longer need the initialisation options.
switch (rc) {
case JNI_OK:
snprintf(g->Message, sizeof (g->Message), "VM successfully created" );
brc = false ;
break ;
case JNI_ERR:
snprintf(g->Message, sizeof (g->Message), "Initialising JVM failed: unknown error" );
break ;
case JNI_EDETACHED:
snprintf(g->Message, sizeof (g->Message), "Thread detached from the VM" );
break ;
case JNI_EVERSION:
snprintf(g->Message, sizeof (g->Message), "JNI version error" );
break ;
case JNI_ENOMEM:
snprintf(g->Message, sizeof (g->Message), "Not enough memory" );
break ;
case JNI_EEXIST:
snprintf(g->Message, sizeof (g->Message), "VM already created" );
break ;
case JNI_EINVAL:
snprintf(g->Message, sizeof (g->Message), "Invalid arguments" );
break ;
default :
snprintf(g->Message, sizeof (g->Message), "Unknown return code %d" , (int )rc);
break ;
} // endswitch rc
if (trace(1 ))
htrc("%s\n" , g->Message);
if (brc)
return true ;
//=============== Display JVM version ===============
jint ver = env->GetVersion();
printf("JVM Version %d.%d\n" , ((ver >> 16 ) & 0 x0f), (ver & 0 x0f));
} // endif rc
// try to find the java wrapper class
jdi = env->FindClass(m_Wrap);
if (jdi == nullptr) {
snprintf(g->Message, sizeof (g->Message), "ERROR: class %s not found!" , m_Wrap);
return true ;
} // endif jdi
#if 0 // Suppressed because it does not make any usable change
if (b && jpath && *jpath) {
// Try to add that path the the jvm class path
jmethodID alp = env->GetStaticMethodID(jdi, "addLibraryPath" ,
"(Ljava/lang/String;)I" );
if (alp == nullptr) {
env->ExceptionDescribe();
env->ExceptionClear();
} else {
char *msg;
jstring path = env->NewStringUTF(jpath);
rc = env->CallStaticIntMethod(jdi, alp, path);
if ((msg = Check(rc))) {
snprintf(g->Message, sizeof (g->Message), msg);
env->DeleteLocalRef(path);
return RC_FX;
} else switch (rc) {
case JNI_OK:
printf("jpath added\n" );
break ;
case JNI_EEXIST:
printf("jpath already exist\n" );
break ;
case JNI_ERR:
default :
snprintf(g->Message, sizeof (g->Message), "Error adding jpath" );
env->DeleteLocalRef(path);
return RC_FX;
} // endswitch rc
env->DeleteLocalRef(path);
} // endif alp
} // endif jpath
#endif // 0
// if class found, continue
jmethodID ctor = env->GetMethodID(jdi, "<init>" , "(Z)V" );
if (ctor == nullptr) {
snprintf(g->Message, sizeof (g->Message), "ERROR: %s constructor not found!" , m_Wrap);
return true ;
} else
job = env->NewObject(jdi, ctor, jt);
if (job == nullptr) {
snprintf(g->Message, sizeof (g->Message), "%s class object not constructed!" , m_Wrap);
return true ;
} // endif job
// If the object is successfully constructed,
// we can then search for the method we want to call,
// and invoke it for the object:
errid = env->GetMethodID(jdi, "GetErrmsg" , "()Ljava/lang/String;" );
if (env->ExceptionCheck()) {
snprintf(g->Message, sizeof (g->Message), "ERROR: method GetErrmsg() not found!" );
env->ExceptionDescribe();
env->ExceptionClear();
return true ;
} // endif Check
/*********************************************************************/
/* Link a Fblock. This make possible to automatically close it */
/* in case of error (throw). */
/*********************************************************************/
PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof (FBLOCK));
fp->Type = TYPE_FB_JAVA;
fp->Fname = NULL;
fp->Next = dbuserp->Openlist;
dbuserp->Openlist = fp;
fp->Count = 1 ;
fp->Length = 0 ;
fp->Memory = NULL;
fp->Mode = MODE_ANY;
fp->File = this ;
fp->Handle = 0 ;
m_Opened = true ;
return false ;
} // end of Open
/***********************************************************************/
/* Disconnect connection */
/***********************************************************************/
void JAVAConn::Close()
{
jint rc;
if (m_Connected) {
jmethodID did = nullptr;
// Could have been detached in case of join
rc = jvm->AttachCurrentThread((void **)&env, nullptr);
if (gmID(m_G, did, DiscFunc, "()I" ))
printf("%s\n" , Msg);
else if (Check(env->CallIntMethod(job, did)))
printf("%s: %s\n" , DiscFunc, Msg);
m_Connected = false ;
} // endif m_Connected
if ((rc = jvm->DetachCurrentThread()) != JNI_OK)
printf("DetachCurrentThread: rc=%d\n" , (int )rc);
if (fp)
fp->Count = 0 ;
m_Opened = false ;
} // end of Close
Messung V0.5 in Prozent C=74 H=99 G=87
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland