/* JSmooth: a VM wrapper toolkit for Windows Copyright (C) 2003-2007 Rodrigo Reyes <reyes@charabia.net> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "SunJVMDLL.h" #include "JClassProxy.h" #include "JniSmooth.h" SunJVMDLL::SunJVMDLL(const std::string& jvmdll, const Version& v) { m_dllpath = jvmdll; m_version = v; m_statusCode = SunJVMDLL::JVM_NOT_STARTED; m_vmlib = NULL; } SunJVMDLL::~SunJVMDLL() { if (m_vmlib != NULL) { FreeLibrary(m_vmlib); } } bool SunJVMDLL::run(const std::string& mainclass, bool waitDeath) { if (m_statusCode == SunJVMDLL::JVM_NOT_STARTED) instanciate(); if (m_statusCode == SunJVMDLL::JVM_LOADED) { JClassProxy disp(this, mainclass); jstring emptystr = newUTFString(std::string("")); jobjectArray mainargs = newObjectArray(m_arguments.size(), "java.lang.String", emptystr); for (int i =0; i<m_arguments.size(); i++) { env()->SetObjectArrayElement(mainargs, i, newUTFString(m_arguments[i])); } printf("arguments array = %d\n", mainargs); jvalue ma[1]; ma[0].l = mainargs; disp.invokeStatic(std::string("void main(java.lang.String[] args)"), ma); if (waitDeath == true) m_javavm->DestroyJavaVM(); return true; } return false; } void SunJVMDLL::join() { if (m_statusCode == SunJVMDLL::JVM_LOADED) { m_javavm->DestroyJavaVM(); } } bool SunJVMDLL::instanciate() { m_vmlib = LoadLibrary(m_dllpath.c_str()); if (m_vmlib == NULL) { m_statusCode = SunJVMDLL::JVM_DLL_CANT_LOAD; return false; } CreateJavaVM_t CreateJavaVM = (CreateJavaVM_t)GetProcAddress(m_vmlib, "JNI_CreateJavaVM"); GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)GetProcAddress(m_vmlib, "JNI_GetDefaultJavaVMInitArgs"); if ((CreateJavaVM == NULL) || (GetDefaultJavaVMInitArgs == NULL)) { m_statusCode = SunJVMDLL::JVM_CANT_USE_VM; return false; } DEBUG("VM Created successfully"); m_javavm = new JavaVM(); m_javaenv = new JNIEnv(); DEBUG("DLL Setup on " + m_version.toString()); bool res; if ((m_version.getMajor() == 1) && (m_version.getMinor() == 1)) res = setupVM11DLL(CreateJavaVM, GetDefaultJavaVMInitArgs); else res = setupVM12DLL(CreateJavaVM, GetDefaultJavaVMInitArgs); registerJniSmooth(); DEBUG("Result code on DLL: " + StringUtils::toString(res)); if (res) { m_statusCode = SunJVMDLL::JVM_LOADED; return true; } m_statusCode = SunJVMDLL::JVM_CANT_USE_VM; return false; } bool SunJVMDLL::setupVM12DLL(CreateJavaVM_t CreateJavaVM, GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs) { vector<string> jpropstrv; for (int i=0; i<m_properties.size(); i++) if(m_properties[i].getName()[0]=='-') { jpropstrv.push_back( StringUtils::requoteForCommandLine(m_properties[i].getName())); } else { jpropstrv.push_back( StringUtils::requoteForCommandLine("-D" + m_properties[i].getName()) + "=" + StringUtils::requoteForCommandLine(m_properties[i].getValue())); } // DEBUG("MAXHEAP: " + StringUtils::toString(m_maxHeap)); // DEBUG("INITIALHEAP: " + StringUtils::toString(m_initialHeap)); if (m_maxHeap > 0) { jpropstrv.push_back("-Xmx" +StringUtils::toString(m_maxHeap)); } if (m_initialHeap > 0) { jpropstrv.push_back("-Xms" + StringUtils::toString(m_initialHeap)); } JavaVMInitArgs vm_args; GetDefaultJavaVMInitArgs(&vm_args); JavaVMOption options[1 + jpropstrv.size()]; std::string cpoption = "-Djava.class.path=" + StringUtils::join(m_pathElements, ";"); DEBUG("Classpath: " + cpoption); options[0].optionString = (char*)cpoption.c_str(); vm_args.version = 0x00010002; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = 1 + jpropstrv.size(); for (int i=0; i<jpropstrv.size(); i++) { options[1 + i].optionString = (char*)jpropstrv[i].c_str(); DEBUG(string("Option added:") + options[1+i].optionString); } vm_args.ignoreUnrecognized = JNI_TRUE; // // Create the VM if (CreateJavaVM( &m_javavm, &m_javaenv, &vm_args) != 0) { DEBUG("Can't create VM"); m_statusCode = SunJVMDLL::JVM_CANT_CREATE_VM; return false; } DEBUG("VM 1.2+ Created successfully !!"); return true; } bool SunJVMDLL::setupVM11DLL(CreateJavaVM_t CreateJavaVM, GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs) { JDK1_1InitArgs vm_args; vm_args.version = 0x00010001; GetDefaultJavaVMInitArgs(&vm_args); if (m_maxHeap > 0) vm_args.maxHeapSize = m_maxHeap; if (m_initialHeap > 0) vm_args.minHeapSize = m_initialHeap; // // create the properties array // char const * props[m_properties.size()+1]; vector<string> jpropstrv; for (int i=0; i<m_properties.size(); i++) jpropstrv[i] = m_properties[i].getName() + "=" + m_properties[i].getValue(); for (int i=0; i<m_properties.size(); i++) props[i] = jpropstrv[i].c_str(); props[m_properties.size()] = NULL; vm_args.properties = (char**)props; /* Append USER_CLASSPATH to the default system class path */ std::string classpath = vm_args.classpath; classpath += StringUtils::join(m_pathElements, ";"); DEBUG("Classpath = " + classpath); vm_args.classpath = (char*)classpath.c_str(); // // Create the VM if (CreateJavaVM( &m_javavm, &m_javaenv, &vm_args) != 0) { DEBUG("Can't create VM"); m_statusCode = SunJVMDLL::JVM_CANT_CREATE_VM; return false; } DEBUG("VM 1.1 Created successfully !!"); return true; } jclass SunJVMDLL::findClass(const std::string& clazz) { std::string classname = StringUtils::replace(clazz,".", "/"); DEBUG("Looking up for class <" + classname + ">"); jclass cls = env()->FindClass(classname.c_str()); if (cls == 0) DEBUG("Can't find class " + classname + " !"); return cls; } jmethodID SunJVMDLL::findMethod(jclass& cls, const std::string& methodname, const std::string& signature, bool isStatic) { std::string sig = StringUtils::replace(signature, ".", "/"); jmethodID mid; if (isStatic) mid = env()->GetStaticMethodID(cls, methodname.c_str(), sig.c_str()); else mid = env()->GetMethodID(cls, methodname.c_str(), sig.c_str()); return mid; } JavaVM* SunJVMDLL::getJavaVM() { return m_javavm; } void SunJVMDLL::setIntField(jclass cls, jobject obj, const std::string& fieldName, int value) { jfieldID binding = env()->GetFieldID(cls, fieldName.c_str(), "I"); env()->SetIntField(obj, binding, (jint)value); } void SunJVMDLL::setLongField(jclass cls, jobject obj, const std::string& fieldName, jlong value) { jfieldID binding = env()->GetFieldID(cls, fieldName.c_str(), "J"); env()->SetLongField(obj, binding, (jlong)value); } void SunJVMDLL::setObjectField(jclass cls, jobject obj, const std::string& fieldName, const std::string& fieldclass, jobject value) { std::string fc = "L" + StringUtils::replace(fieldclass, "." , "/") + ";"; jfieldID binding = env()->GetFieldID(cls, fieldName.c_str(), fc.c_str()); env()->SetObjectField(obj, binding, value); } jstring SunJVMDLL::newUTFString(const std::string& str) { return env()->NewStringUTF(str.c_str()); } jobject SunJVMDLL::newObject(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->NewObjectA(clazz, methodid, arguments); } jobjectArray SunJVMDLL::newObjectArray(int size, jclass clazz, jobject initialValue) { return env()->NewObjectArray((jsize)size, clazz, initialValue); } jobjectArray SunJVMDLL::newObjectArray(int size, const std::string& classname, jobject initialValue) { jclass cls = findClass(classname); return newObjectArray(size, cls, initialValue); } // // Static method invocation // void SunJVMDLL::invokeVoidStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { env()->CallStaticVoidMethodA(clazz, methodid, arguments); } jboolean SunJVMDLL::invokeBooleanStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticBooleanMethodA(clazz, methodid, arguments); } jbyte SunJVMDLL::invokeByteStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticByteMethodA(clazz, methodid, arguments); } jchar SunJVMDLL::invokeCharStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticCharMethodA(clazz, methodid, arguments); } jshort SunJVMDLL::invokeShortStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticShortMethodA(clazz, methodid, arguments); } jint SunJVMDLL::invokeIntStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticIntMethodA(clazz, methodid, arguments); } jlong SunJVMDLL::invokeLongStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticLongMethodA(clazz, methodid, arguments); } jfloat SunJVMDLL::invokeFloatStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticFloatMethodA(clazz, methodid, arguments); } jdouble SunJVMDLL::invokeDoubleStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticDoubleMethodA(clazz, methodid, arguments); } jobject SunJVMDLL::invokeObjectStatic(jclass clazz, jmethodID& methodid, jvalue arguments[]) { return env()->CallStaticObjectMethodA(clazz, methodid, arguments); } // // method invocation // void SunJVMDLL::invokeVoid(jobject& obj, jmethodID& methodid, jvalue arguments[]) { env()->CallVoidMethodA(obj, methodid, arguments); } jboolean SunJVMDLL::invokeBoolean(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallBooleanMethodA(obj, methodid, arguments); } jbyte SunJVMDLL::invokeByte(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallByteMethodA(obj, methodid, arguments); } jchar SunJVMDLL::invokeChar(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallCharMethodA(obj, methodid, arguments); } jshort SunJVMDLL::invokeShort(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallShortMethodA(obj, methodid, arguments); } jint SunJVMDLL::invokeInt(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallIntMethodA(obj, methodid, arguments); } jlong SunJVMDLL::invokeLong(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallLongMethodA(obj, methodid, arguments); } jfloat SunJVMDLL::invokeFloat(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallFloatMethodA(obj, methodid, arguments); } jdouble SunJVMDLL::invokeDouble(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallDoubleMethodA(obj, methodid, arguments); } jobject SunJVMDLL::invokeObject(jobject& obj, jmethodID& methodid, jvalue arguments[]) { return env()->CallObjectMethodA(obj, methodid, arguments); } bool SunJVMDLL::registerMethod(const std::string& classname, const std::string& methodname, const std::string& signature, void* fn) { jclass cc = this->findClass(classname); if (cc == 0) return false; JNINativeMethod jnm; jnm.name = (char*)methodname.c_str(); jnm.signature = (char*)signature.c_str(); jnm.fnPtr = fn; int res = env()->RegisterNatives(cc, &jnm, 1); if (res != 0) return false; return true; } bool SunJVMDLL::registerJniSmooth() { registerNativeMethods(this); return true; }