|
@@ -30,6 +30,8 @@
|
|
|
#include "build-config.h"
|
|
|
#include "roxiemem.hpp"
|
|
|
#include "nbcd.hpp"
|
|
|
+#include "thorxmlwrite.hpp"
|
|
|
+#include "esdl_def.hpp"
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#define EXPORT __declspec(dllexport)
|
|
@@ -225,7 +227,7 @@ static void checkType(type_t javatype, size32_t javasize, type_t ecltype, size32
|
|
|
throw MakeStringException(0, "javaembed: Type mismatch"); // MORE - could provide some details!
|
|
|
}
|
|
|
|
|
|
-static void checkException(JNIEnv *JNIenv)
|
|
|
+static void checkException(JNIEnv *JNIenv, bool fail=true)
|
|
|
{
|
|
|
if (JNIenv->ExceptionCheck())
|
|
|
{
|
|
@@ -237,7 +239,9 @@ static void checkException(JNIEnv *JNIenv)
|
|
|
const char *text = JNIenv->GetStringUTFChars(cause, 0);
|
|
|
VStringBuffer message("javaembed: %s", text);
|
|
|
JNIenv->ReleaseStringUTFChars(cause, text);
|
|
|
- rtlFail(0, message.str());
|
|
|
+ if (fail)
|
|
|
+ rtlFail(0, message);
|
|
|
+ throw MakeStringExceptionDirect(0, message);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1153,6 +1157,272 @@ protected:
|
|
|
jobject iterator;;
|
|
|
};
|
|
|
|
|
|
+const char *esdl2JavaSig(IEsdlDefinition &esdl, const char *esdlType)
|
|
|
+{
|
|
|
+ EsdlBasicElementType t = esdl.translateSimpleType(esdlType);
|
|
|
+ switch (t)
|
|
|
+ {
|
|
|
+ case ESDLT_INT16:
|
|
|
+ case ESDLT_UINT16:
|
|
|
+ return "Ljava/lang/Short;";
|
|
|
+ case ESDLT_INT32:
|
|
|
+ case ESDLT_UINT32:
|
|
|
+ return "Ljava/lang/Integer;";
|
|
|
+ case ESDLT_INT64:
|
|
|
+ case ESDLT_UINT64:
|
|
|
+ return "Ljava/math/BigInteger;";
|
|
|
+ case ESDLT_BOOL:
|
|
|
+ return "Ljava/lang/Boolean;";
|
|
|
+ case ESDLT_FLOAT:
|
|
|
+ return "Ljava/lang/Float;";
|
|
|
+ case ESDLT_DOUBLE:
|
|
|
+ return "Ljava/lang/Double;";
|
|
|
+ case ESDLT_INT8:
|
|
|
+ case ESDLT_UINT8:
|
|
|
+ case ESDLT_BYTE:
|
|
|
+ case ESDLT_UBYTE:
|
|
|
+ return "Ljava/lang/Byte;";
|
|
|
+ case ESDLT_STRING:
|
|
|
+ return "Ljava/lang/String;";
|
|
|
+ case ESDLT_UNKOWN:
|
|
|
+ case ESDLT_STRUCT:
|
|
|
+ case ESDLT_REQUEST:
|
|
|
+ case ESDLT_RESPONSE:
|
|
|
+ case ESDLT_COMPLEX:
|
|
|
+ default:
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const char *esdl2JavaFullClassName(IEsdlDefinition &esdl, const char *esdlType)
|
|
|
+{
|
|
|
+ EsdlBasicElementType t = esdl.translateSimpleType(esdlType);
|
|
|
+ switch (t)
|
|
|
+ {
|
|
|
+ case ESDLT_INT16:
|
|
|
+ case ESDLT_UINT16:
|
|
|
+ return "java/lang/Short";
|
|
|
+ case ESDLT_INT32:
|
|
|
+ case ESDLT_UINT32:
|
|
|
+ return "java/lang/Integer";
|
|
|
+ case ESDLT_INT64:
|
|
|
+ case ESDLT_UINT64:
|
|
|
+ return "java/math/BigInteger";
|
|
|
+ case ESDLT_BOOL:
|
|
|
+ return "java/lang/Boolean";
|
|
|
+ case ESDLT_FLOAT:
|
|
|
+ return "java/lang/Float";
|
|
|
+ case ESDLT_DOUBLE:
|
|
|
+ return "java/lang/Double";
|
|
|
+ case ESDLT_INT8:
|
|
|
+ case ESDLT_UINT8:
|
|
|
+ case ESDLT_BYTE:
|
|
|
+ case ESDLT_UBYTE:
|
|
|
+ return "java/lang/Byte";
|
|
|
+ case ESDLT_STRING:
|
|
|
+ return "java/lang/String";
|
|
|
+ case ESDLT_UNKOWN:
|
|
|
+ case ESDLT_STRUCT:
|
|
|
+ case ESDLT_REQUEST:
|
|
|
+ case ESDLT_RESPONSE:
|
|
|
+ case ESDLT_COMPLEX:
|
|
|
+ default:
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class JavaObjectXmlWriter : public CInterface
|
|
|
+{
|
|
|
+public:
|
|
|
+ JavaObjectXmlWriter(JNIEnv *_JNIenv, jobject _obj, const char *_reqType, IEsdlDefinition &_esdl, const char *_esdlService, IXmlWriter &_writer)
|
|
|
+ : JNIenv(_JNIenv), obj(_obj), writer(_writer), esdl(_esdl), esdlService(_esdlService), reqType(_reqType)
|
|
|
+ {
|
|
|
+ Class = (jclass) JNIenv->NewGlobalRef(JNIenv->GetObjectClass(obj));
|
|
|
+ langObjectClass = FindClass("java/lang/Object");
|
|
|
+ objToString = JNIenv->GetMethodID(langObjectClass, "toString", "()Ljava/lang/String;");
|
|
|
+ }
|
|
|
+ ~JavaObjectXmlWriter()
|
|
|
+ {
|
|
|
+ if (Class)
|
|
|
+ JNIenv->DeleteGlobalRef(Class);
|
|
|
+ HashIterator it(javaClasses);
|
|
|
+ ForEach(it)
|
|
|
+ {
|
|
|
+ IMapping &entry = it.query();
|
|
|
+ jclass *pClass = javaClasses.mapToValue(&entry);
|
|
|
+ if (pClass)
|
|
|
+ JNIenv->DeleteGlobalRef(*pClass);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void writeSimpleType(jclass parentClass, jobject parentObject, IEsdlDefObject &defObject)
|
|
|
+ {
|
|
|
+ const char *fieldname = defObject.queryName();
|
|
|
+ const char *javaSig = esdl2JavaSig(esdl, defObject.queryProp("type"));
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(parentClass, fieldname, javaSig); //tbd cache this
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+ jobject fieldObj = (jobject) JNIenv->GetObjectField(parentObject, fieldId);
|
|
|
+ if (!fieldObj)
|
|
|
+ return;
|
|
|
+ jstring fieldStr = (jstring) JNIenv->CallObjectMethod(fieldObj, objToString);
|
|
|
+ const char *text = JNIenv->GetStringUTFChars(fieldStr, NULL);
|
|
|
+ if (!text)
|
|
|
+ return;
|
|
|
+ writer.outputCString(text, defObject.queryName());
|
|
|
+ }
|
|
|
+ void writeEnumType(jclass parentClass, jobject parentObject, IEsdlDefObject &defObject)
|
|
|
+ {
|
|
|
+ const char *fieldname = defObject.queryName();
|
|
|
+ VStringBuffer javaSig("L%s/%s;", esdlService.str(), defObject.queryProp("enum_type"));
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(parentClass, fieldname, javaSig);
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+ jobject fieldObj = (jobject) JNIenv->GetObjectField(parentObject, fieldId);
|
|
|
+ if (!fieldObj)
|
|
|
+ return;
|
|
|
+ jstring fieldStr = (jstring) JNIenv->CallObjectMethod(fieldObj, objToString);
|
|
|
+ const char *text = JNIenv->GetStringUTFChars(fieldStr, NULL);
|
|
|
+ if (!text)
|
|
|
+ return;
|
|
|
+ writer.outputCString(text, defObject.queryName());
|
|
|
+ }
|
|
|
+ void writeComplexType(jclass parentClass, jobject parentObject, IEsdlDefObject &defObject)
|
|
|
+ {
|
|
|
+ IEsdlDefStruct *defStruct = esdl.queryStruct(defObject.queryProp("complex_type"));
|
|
|
+ if (!defStruct)
|
|
|
+ return;
|
|
|
+ const char *fieldname = defObject.queryName();
|
|
|
+ VStringBuffer javaSig("L%s/%s;", esdlService.str(), defObject.queryProp("complex_type"));
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(parentClass, fieldname, javaSig); //tbd cache this
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+ jobject fieldObj = (jobject) JNIenv->GetObjectField(parentObject, fieldId);
|
|
|
+ if (!fieldObj)
|
|
|
+ return;
|
|
|
+ writer.outputBeginNested(fieldname, true);
|
|
|
+ writeChildren(JNIenv->GetObjectClass(fieldObj), fieldObj, defStruct);
|
|
|
+ writer.outputEndNested(fieldname);
|
|
|
+ }
|
|
|
+ void writeSimpleArray(jclass parentClass, jobject parentObject, IEsdlDefObject &defObject)
|
|
|
+ {
|
|
|
+ //tbd
|
|
|
+ }
|
|
|
+ void writeComplexArray(jclass parentClass, jobject parentObject, IEsdlDefObject &defObject)
|
|
|
+ {
|
|
|
+ IEsdlDefStruct *defStruct = esdl.queryStruct(defObject.queryProp("type"));
|
|
|
+ if (!defStruct)
|
|
|
+ return;
|
|
|
+ const char *fieldname = defObject.queryName();
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(parentClass, fieldname, "Ljava/util/ArrayList;");
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+ jobject arrayListObj = (jobject) JNIenv->GetObjectField(parentObject, fieldId);
|
|
|
+ if (!arrayListObj)
|
|
|
+ return;
|
|
|
+ jclass arrayListClass = FindClass("java/util/ArrayList");
|
|
|
+ if (!arrayListClass)
|
|
|
+ return;
|
|
|
+ jmethodID toArrayMethod = JNIenv->GetMethodID(arrayListClass, "toArray", "()[Ljava/lang/Object;" );
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ if (!toArrayMethod)
|
|
|
+ return;
|
|
|
+
|
|
|
+ VStringBuffer javaClassName("%s/%s", esdlService.str(), defObject.queryProp("type"));
|
|
|
+ jclass elementClass = FindClass(javaClassName);
|
|
|
+ if (!elementClass)
|
|
|
+ return;
|
|
|
+ const char *item_tag = defObject.queryProp("item_tag");
|
|
|
+ writer.outputBeginNested(defObject.queryName(), true);
|
|
|
+ writer.outputBeginArray(item_tag);
|
|
|
+ jobjectArray arrayObj = (jobjectArray) JNIenv->CallObjectMethod(arrayListObj, toArrayMethod);
|
|
|
+ jint i;
|
|
|
+ jint count = JNIenv->GetArrayLength(arrayObj);
|
|
|
+ for (i=0; i < count; i++)
|
|
|
+ {
|
|
|
+ jobject elementObj = JNIenv->GetObjectArrayElement(arrayObj, i);
|
|
|
+ if(JNIenv->ExceptionOccurred())
|
|
|
+ break;
|
|
|
+ writer.outputBeginNested(item_tag, true);
|
|
|
+ writeChildren(elementClass, elementObj, defStruct);
|
|
|
+ writer.outputEndNested(item_tag);
|
|
|
+ JNIenv->DeleteLocalRef(elementObj);
|
|
|
+ }
|
|
|
+ writer.outputEndArray(item_tag);
|
|
|
+ writer.outputEndNested(defObject.queryName());
|
|
|
+ }
|
|
|
+ void writeChildren(jclass javaClass, jobject javaObject, IEsdlDefStruct *defStruct)
|
|
|
+ {
|
|
|
+ Owned<IEsdlDefObjectIterator> children = defStruct->getChildren();
|
|
|
+ ForEach (*children)
|
|
|
+ {
|
|
|
+ IEsdlDefObject &child = children->query();
|
|
|
+ if (child.getEsdlType()==EsdlTypeElement)
|
|
|
+ {
|
|
|
+ if (child.hasProp("type"))
|
|
|
+ writeSimpleType(javaClass, javaObject, child);
|
|
|
+ else if (child.hasProp("complex_type"))
|
|
|
+ writeComplexType(javaClass, javaObject, child);
|
|
|
+ }
|
|
|
+ else if (child.getEsdlType()==EsdlTypeEnumRef)
|
|
|
+ {
|
|
|
+ writeEnumType(javaClass, javaObject, child);
|
|
|
+ }
|
|
|
+ else if (child.getEsdlType()==EsdlTypeArray)
|
|
|
+ {
|
|
|
+ writeComplexArray(javaClass, javaObject, child); //adf: tbd handle simple array
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ void write()
|
|
|
+ {
|
|
|
+ IEsdlDefStruct *reqStruct = esdl.queryStruct(reqType);
|
|
|
+ const char *name = reqStruct->queryName();
|
|
|
+ writer.outputBeginNested("Response", true);
|
|
|
+ writer.outputBeginNested("Results", true);
|
|
|
+ writer.outputBeginNested("Result", true);
|
|
|
+ writer.outputBeginDataset(name, true);
|
|
|
+ writer.outputBeginArray("Row");
|
|
|
+ writer.outputBeginNested("Row", true);
|
|
|
+ writeChildren(Class, obj, reqStruct);
|
|
|
+ writer.outputEndNested("Row");
|
|
|
+ writer.outputEndArray("Row");
|
|
|
+ writer.outputEndDataset(name);
|
|
|
+ writer.outputEndNested("Result");
|
|
|
+ writer.outputEndNested("Results");
|
|
|
+ writer.outputEndNested("Response");
|
|
|
+ }
|
|
|
+
|
|
|
+ void checkException()
|
|
|
+ {
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ jclass FindClass(const char *name)
|
|
|
+ {
|
|
|
+ jclass *pClass = javaClasses.getValue(name);
|
|
|
+ if (pClass)
|
|
|
+ return *pClass;
|
|
|
+ jclass localClass = JNIenv->FindClass(name);
|
|
|
+ if (!localClass)
|
|
|
+ return 0;
|
|
|
+ jclass Class = (jclass) JNIenv->NewGlobalRef(localClass);
|
|
|
+ javaClasses.setValue(name, Class);
|
|
|
+ JNIenv->DeleteLocalRef(localClass);
|
|
|
+ return Class;
|
|
|
+ }
|
|
|
+
|
|
|
+ JNIEnv *JNIenv;
|
|
|
+ MapStringTo<jclass> javaClasses;
|
|
|
+ jclass Class;
|
|
|
+ jobject obj;
|
|
|
+ jclass langObjectClass;
|
|
|
+ jmethodID objToString;
|
|
|
+ IXmlWriter &writer;
|
|
|
+ IEsdlDefinition &esdl;
|
|
|
+ StringAttr reqType;
|
|
|
+ StringAttr esdlService;
|
|
|
+};
|
|
|
|
|
|
//-------------------------------------------
|
|
|
|
|
@@ -1292,11 +1562,12 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- inline void importFunction(size32_t lenChars, const char *utf, const char *options)
|
|
|
+ inline void importFunction(size32_t lenChars, const char *utf, const char *options, jobject instance)
|
|
|
{
|
|
|
size32_t bytes = rtlUtf8Size(lenChars, utf);
|
|
|
StringBuffer text(bytes, utf);
|
|
|
setThreadClassLoader(options);
|
|
|
+
|
|
|
if (!prevtext || strcmp(text, prevtext) != 0)
|
|
|
{
|
|
|
prevtext.clear();
|
|
@@ -1347,7 +1618,10 @@ public:
|
|
|
|
|
|
if (!javaClass)
|
|
|
throw MakeStringException(MSGAUD_user, 0, "javaembed: Failed to resolve class name %s", classname.str());
|
|
|
- javaMethodID = JNIenv->GetStaticMethodID(javaClass, methodname, javaSignature);
|
|
|
+ if (instance)
|
|
|
+ javaMethodID = JNIenv->GetMethodID(javaClass, methodname, javaSignature);
|
|
|
+ else
|
|
|
+ javaMethodID = JNIenv->GetStaticMethodID(javaClass, methodname, javaSignature);
|
|
|
if (!javaMethodID)
|
|
|
throw MakeStringException(MSGAUD_user, 0, "javaembed: Failed to resolve method name %s with signature %s", methodname.str(), signature);
|
|
|
const char *returnSig = strrchr(signature, ')');
|
|
@@ -1358,6 +1632,27 @@ public:
|
|
|
prevtext.set(text);
|
|
|
}
|
|
|
}
|
|
|
+ inline void callFunction(jvalue &result, const jvalue * args, jobject instance)
|
|
|
+ {
|
|
|
+ JNIenv->ExceptionClear();
|
|
|
+ switch (returnType.get()[0])
|
|
|
+ {
|
|
|
+ case 'C': result.c = JNIenv->CallCharMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'Z': result.z = JNIenv->CallBooleanMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'J': result.j = JNIenv->CallLongMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'F': result.f = JNIenv->CallFloatMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'D': result.d = JNIenv->CallDoubleMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'I': result.i = JNIenv->CallIntMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'S': result.s = JNIenv->CallShortMethodA(instance, javaMethodID, args); break;
|
|
|
+ case 'B': result.s = JNIenv->CallByteMethodA(instance, javaMethodID, args); break;
|
|
|
+
|
|
|
+ case '[':
|
|
|
+ case 'L': result.l = JNIenv->CallObjectMethodA(instance, javaMethodID, args); break;
|
|
|
+
|
|
|
+ default: throwUnexpected();
|
|
|
+ }
|
|
|
+ checkException();
|
|
|
+ }
|
|
|
inline void callFunction(jvalue &result, const jvalue * args)
|
|
|
{
|
|
|
JNIenv->ExceptionClear();
|
|
@@ -1684,6 +1979,11 @@ public:
|
|
|
JavaRowBuilder javaRowBuilder(JNIenv, &dummyField, result);
|
|
|
return typeInfo->build(builder, 0, &dummyField, javaRowBuilder);
|
|
|
}
|
|
|
+ void writeObjectResult(jobject result, IEsdlDefinition *esdl, const char *esdlservice, const char *name, IXmlWriter *writer)
|
|
|
+ {
|
|
|
+ JavaObjectXmlWriter x(JNIenv, result, name, *esdl, esdlservice, *writer);
|
|
|
+ x.write();
|
|
|
+ }
|
|
|
|
|
|
private:
|
|
|
StringAttr returnType;
|
|
@@ -1694,14 +1994,404 @@ private:
|
|
|
jmethodID javaMethodID;
|
|
|
};
|
|
|
|
|
|
+class JavaXmlBuilder : public CInterface, implements IXmlWriterExt
|
|
|
+{
|
|
|
+public:
|
|
|
+ IMPLEMENT_IINTERFACE;
|
|
|
+ JavaXmlBuilder(JNIEnv *_JNIenv, IEsdlDefinition *esdl_, const char *esdlservice, const char *esdltype_)
|
|
|
+ : JNIenv(_JNIenv), esdl(esdl_), javaPackage(esdlservice), esdlType(esdltype_)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ ~JavaXmlBuilder()
|
|
|
+ {
|
|
|
+ while (defStack.length())
|
|
|
+ popDefStackEntry(JNIenv);
|
|
|
+ HashIterator it(javaClasses);
|
|
|
+ ForEach(it)
|
|
|
+ {
|
|
|
+ IMapping &entry = it.query();
|
|
|
+ jclass *pClass = javaClasses.mapToValue(&entry);
|
|
|
+ if (pClass)
|
|
|
+ JNIenv->DeleteGlobalRef(*pClass);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ void checkException()
|
|
|
+ {
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ void initWriter()
|
|
|
+ {
|
|
|
+ }
|
|
|
+ IXmlWriterExt & clear()
|
|
|
+ {
|
|
|
+ UNIMPLEMENTED;
|
|
|
+ }
|
|
|
+ virtual size32_t length() const
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ virtual const char *str() const
|
|
|
+ {
|
|
|
+ UNIMPLEMENTED;
|
|
|
+ }
|
|
|
+ virtual void rewindTo(unsigned int prevlen)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ inline IEsdlDefStruct *queryCurrentEsdlStruct()
|
|
|
+ {
|
|
|
+ if (!defStack.length() || !defStack.tos().defType)
|
|
|
+ return NULL;
|
|
|
+ return dynamic_cast<IEsdlDefStruct*>(defStack.tos().defType.get());
|
|
|
+ }
|
|
|
+ inline jobject getObject()
|
|
|
+ {
|
|
|
+ if (!defStack.length())
|
|
|
+ return 0;
|
|
|
+ return defStack.item(0).obj;
|
|
|
+ }
|
|
|
+ inline jobject getCurJavaObject()
|
|
|
+ {
|
|
|
+ if (!defStack.length())
|
|
|
+ return 0;
|
|
|
+ return defStack.tos().obj;
|
|
|
+ }
|
|
|
+ inline jclass getCurJavaClass()
|
|
|
+ {
|
|
|
+ if (!defStack.length())
|
|
|
+ return 0;
|
|
|
+ return defStack.tos().Class;
|
|
|
+ }
|
|
|
+ inline jmethodID getCurJavaConstructor()
|
|
|
+ {
|
|
|
+ if (!defStack.length())
|
|
|
+ return 0;
|
|
|
+ return defStack.tos().constructor;
|
|
|
+ }
|
|
|
+ virtual void outputEnumString(unsigned size, const char *text, const char *fieldname, IEsdlDefObject *defField)
|
|
|
+ {
|
|
|
+ const char *enum_type = defField->queryProp("enum_type");
|
|
|
+ if (!enum_type || !*enum_type)
|
|
|
+ return;
|
|
|
+ VStringBuffer enumClassName("%s/%s", javaPackage.str(), enum_type);
|
|
|
+ VStringBuffer enumSig("L%s;", enumClassName.str());
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(getCurJavaClass(), fieldname, enumSig);
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+
|
|
|
+ jclass enumClass = FindClass(enumClassName);
|
|
|
+ jmethodID fromString = JNIenv->GetStaticMethodID(enumClass, "fromString", "(Ljava/lang/String;)LEsdlExample/AddressType;"); //All types currently used for ESDL mapping have string constructors
|
|
|
+ StringAttr s(text, size);
|
|
|
+ jstring strvalue = JNIenv->NewStringUTF(s);
|
|
|
+ jobject value = JNIenv->CallStaticObjectMethod(enumClass, fromString, strvalue);
|
|
|
+ JNIenv->DeleteLocalRef(strvalue);
|
|
|
+ checkException();
|
|
|
+ JNIenv->SetObjectField(getCurJavaObject(), fieldId, value);
|
|
|
+ JNIenv->DeleteLocalRef(value);
|
|
|
+ checkException();
|
|
|
+ }
|
|
|
+ virtual void outputString(unsigned size, const char *text, const char *fieldname)
|
|
|
+ {
|
|
|
+ IEsdlDefStruct *defStruct = queryCurrentEsdlStruct();
|
|
|
+ if (!defStruct)
|
|
|
+ return;
|
|
|
+ IEsdlDefObject *defField = defStruct->queryChild(fieldname);
|
|
|
+ if (!defField)
|
|
|
+ return;
|
|
|
+ if (defField->getEsdlType()==EsdlTypeEnumRef)
|
|
|
+ return outputEnumString(size, text, fieldname, defField);
|
|
|
+
|
|
|
+ const char *defType = defField->queryProp("type");
|
|
|
+ if (!defType)
|
|
|
+ return;
|
|
|
+ const char *javaSig = esdl2JavaSig(*esdl, defType);
|
|
|
+ jfieldID fieldId = JNIenv->GetFieldID(getCurJavaClass(), fieldname, javaSig); //tbd cache this
|
|
|
+ if (!fieldId)
|
|
|
+ return;
|
|
|
+
|
|
|
+ const char *fieldClassName = esdl2JavaFullClassName(*esdl, defType);
|
|
|
+ jclass typeClass = FindClass(fieldClassName);
|
|
|
+ jmethodID typeStringConstructor = JNIenv->GetMethodID(typeClass, "<init>", "(Ljava/lang/String;)V"); //All types currently used for ESDL mapping have string constructors
|
|
|
+ StringAttr s(text, size);
|
|
|
+ jstring strvalue = JNIenv->NewStringUTF(s);
|
|
|
+ jobject value = JNIenv->NewObject(typeClass, typeStringConstructor, strvalue);
|
|
|
+ JNIenv->DeleteLocalRef(strvalue);
|
|
|
+ checkException();
|
|
|
+ JNIenv->SetObjectField(getCurJavaObject(), fieldId, value);
|
|
|
+ JNIenv->DeleteLocalRef(value);
|
|
|
+ checkException();
|
|
|
+ }
|
|
|
+ void outputString(const char *text, const char *fieldname)
|
|
|
+ {
|
|
|
+ outputString((unsigned)strlen(text), text, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputNumericString(const char *field, const char *fieldname)
|
|
|
+ {
|
|
|
+ outputString(field, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputBool(bool value, const char *fieldname)
|
|
|
+ {
|
|
|
+ outputString(value ? "true" : "false", fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputUInt(unsigned __int64 field, unsigned size, const char *fieldname)
|
|
|
+ {
|
|
|
+ StringBuffer value;
|
|
|
+ value.append(field);
|
|
|
+ outputString(value.length(), value, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputInt(__int64 field, unsigned size, const char *fieldname)
|
|
|
+ {
|
|
|
+ StringBuffer value;
|
|
|
+ value.append(field);
|
|
|
+ outputString(value.length(), value, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputReal(double field, const char *fieldname)
|
|
|
+ {
|
|
|
+ StringBuffer value;
|
|
|
+ value.append(field);
|
|
|
+ outputString(value.length(), value, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
|
|
|
+ {
|
|
|
+ Decimal d;
|
|
|
+ d.setDecimal(size, precision, field);
|
|
|
+ outputString(d.getCString(), fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
|
|
|
+ {
|
|
|
+ Decimal d;
|
|
|
+ d.setUDecimal(size, precision, field);
|
|
|
+ outputString(d.getCString(), fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputQString(unsigned len, const char *field, const char *fieldname)
|
|
|
+ {
|
|
|
+ MemoryAttr tempBuffer;
|
|
|
+ char * temp;
|
|
|
+ if (len <= 100)
|
|
|
+ temp = (char *)alloca(len);
|
|
|
+ else
|
|
|
+ temp = (char *)tempBuffer.allocate(len);
|
|
|
+ rtlQStrToStr(len, temp, len, field);
|
|
|
+ outputString(len, temp, fieldname);
|
|
|
+ }
|
|
|
+ virtual void outputUnicode(unsigned len, const UChar *field, const char *fieldname)
|
|
|
+ {
|
|
|
+ char * buff = 0;
|
|
|
+ unsigned bufflen = 0;
|
|
|
+ rtlUnicodeToCodepageX(bufflen, buff, len, field, "utf-8");
|
|
|
+ outputString(bufflen, buff, fieldname);
|
|
|
+ rtlFree(buff);
|
|
|
+ }
|
|
|
+ virtual void outputUtf8(unsigned len, const char *field, const char *fieldname)
|
|
|
+ {
|
|
|
+ outputString(len, field, fieldname);
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void outputData(unsigned len, const void *value, const char *fieldname)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputQuoted(const char *text) //would have to let beginNested represent simple types with content set using this?
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputBeginDataset(const char *dsname, bool nestChildren) //not used by ESDL engine
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputEndDataset(const char *dsname)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ inline IEsdlDefObject *queryChildStructDefObj(IEsdlDefObject *child)
|
|
|
+ {
|
|
|
+ if (child)
|
|
|
+ {
|
|
|
+ switch (child->getEsdlType())
|
|
|
+ {
|
|
|
+ case EsdlTypeArray:
|
|
|
+ {
|
|
|
+ const char *structType = child->queryProp("type");
|
|
|
+ if (structType)
|
|
|
+ return esdl->queryObj(structType);
|
|
|
+ }
|
|
|
+ case EsdlTypeElement:
|
|
|
+ {
|
|
|
+ const char *structType = child->queryProp("complex_type");
|
|
|
+ if (structType)
|
|
|
+ return esdl->queryObj(structType);
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ virtual void outputBeginNested(const char *fieldname, bool nestChildren)
|
|
|
+ {
|
|
|
+ IEsdlDefStruct *defStruct = NULL;
|
|
|
+ IEsdlDefObject *defField = NULL;
|
|
|
+ IEsdlDefObject *defType = NULL;
|
|
|
+ if (!defStack.length())
|
|
|
+ {
|
|
|
+ defType = esdl->queryObj(fieldname);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DefStackEntry &parent = defStack.tos();
|
|
|
+ if (parent.defObj && parent.defObj->getEsdlType()==EsdlTypeArray)
|
|
|
+ {
|
|
|
+ defType = parent.defType;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ defStruct = queryCurrentEsdlStruct();
|
|
|
+ if (defStruct)
|
|
|
+ {
|
|
|
+ defField = defStruct->queryChild(fieldname);
|
|
|
+ if (defField)
|
|
|
+ defType = queryChildStructDefObj(defField);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pushDefStackEntry(JNIenv, javaPackage, fieldname, defType, defField);
|
|
|
+ }
|
|
|
+ virtual void outputEndNested(const char *fieldname)
|
|
|
+ {
|
|
|
+ if (defStack.length()>1 && streq(fieldname, defStack.tos().name)) //don't destroy root object yet
|
|
|
+ popDefStackEntry(JNIenv);
|
|
|
+ }
|
|
|
+ virtual void outputSetAll()
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputBeginArray(const char *fieldname)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputEndArray(const char *fieldname)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputInlineXml(const char *text)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ virtual void outputXmlns(const char *name, const char *uri)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+public:
|
|
|
+ JNIEnv *JNIenv;
|
|
|
+ StringAttr javaPackage;
|
|
|
+ StringAttr esdlType;
|
|
|
+ Linked<IEsdlDefinition> esdl;
|
|
|
+ class DefStackEntry : public CInterface, implements IInterface
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ IMPLEMENT_IINTERFACE;
|
|
|
+ DefStackEntry(const char *fieldname, IEsdlDefObject *_defType, IEsdlDefObject *_defObj) : name(fieldname), defType(_defType), defObj(_defObj)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ ~DefStackEntry()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ public:
|
|
|
+ Linked<IEsdlDefObject> defType;
|
|
|
+ Linked<IEsdlDefObject> defObj;
|
|
|
+ StringAttr name;
|
|
|
+ jclass Class;
|
|
|
+ jmethodID constructor;
|
|
|
+ jmethodID append;
|
|
|
+ jfieldID fieldId;
|
|
|
+ jobject obj;
|
|
|
+ };
|
|
|
+
|
|
|
+ jclass FindClass(const char *name)
|
|
|
+ {
|
|
|
+ jclass *pClass = javaClasses.getValue(name);
|
|
|
+ if (pClass)
|
|
|
+ return *pClass;
|
|
|
+ jclass localClass = JNIenv->FindClass(name);
|
|
|
+ if (!localClass)
|
|
|
+ return 0;
|
|
|
+ jclass Class = (jclass) JNIenv->NewGlobalRef(localClass);
|
|
|
+ javaClasses.setValue(name, Class);
|
|
|
+ JNIenv->DeleteLocalRef(localClass);
|
|
|
+ return Class;
|
|
|
+ }
|
|
|
+ void popDefStackEntry(JNIEnv *JNIenv)
|
|
|
+ {
|
|
|
+ Owned<DefStackEntry> entry = &defStack.popGet();
|
|
|
+ if (entry->obj)
|
|
|
+ JNIenv->DeleteGlobalRef(entry->obj);
|
|
|
+ }
|
|
|
+ void pushDefStackEntry(JNIEnv *JNIenv, const char *package, const char *fieldname, IEsdlDefObject *defType, IEsdlDefObject *defObject)
|
|
|
+ {
|
|
|
+ DefStackEntry *parent = defStack.length() ? &defStack.tos() : NULL;
|
|
|
+ Owned<DefStackEntry> entry = new DefStackEntry(fieldname, defType, defObject);
|
|
|
+ JNIenv->ExceptionClear();
|
|
|
+ if (defObject && defObject->getEsdlType()==EsdlTypeArray)
|
|
|
+ {
|
|
|
+ const char *javaClassName = "java/util/ArrayList";
|
|
|
+ entry->Class = FindClass(javaClassName);
|
|
|
+ if (entry->Class)
|
|
|
+ {
|
|
|
+ entry->constructor = JNIenv->GetMethodID(entry->Class, "<init>", "()V");
|
|
|
+ entry->append = JNIenv->GetMethodID(entry->Class, "add", "(Ljava/lang/Object;)Z");
|
|
|
+ jobject localObj = JNIenv->NewObject(entry->Class, entry->constructor);
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ if (localObj)
|
|
|
+ {
|
|
|
+ entry->obj = JNIenv->NewGlobalRef(localObj);
|
|
|
+ if (parent && parent->Class)
|
|
|
+ {
|
|
|
+ VStringBuffer javaSig("L%s;", javaClassName);
|
|
|
+ entry->fieldId = JNIenv->GetFieldID(parent->Class, fieldname, javaSig);
|
|
|
+ if (parent->obj && entry->fieldId)
|
|
|
+ JNIenv->SetObjectField(parent->obj, entry->fieldId, entry->obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (defType)
|
|
|
+ {
|
|
|
+ VStringBuffer javaClassName("%s/%s", package, defType->queryName());
|
|
|
+ entry->Class = FindClass(javaClassName);
|
|
|
+ if (entry->Class)
|
|
|
+ {
|
|
|
+ entry->constructor = JNIenv->GetMethodID(entry->Class, "<init>", "()V");
|
|
|
+ jobject localObj = JNIenv->NewObject(entry->Class, entry->constructor);
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ if (localObj)
|
|
|
+ {
|
|
|
+ entry->obj = JNIenv->NewGlobalRef(localObj);
|
|
|
+ if (parent)
|
|
|
+ {
|
|
|
+ if (parent->defObj && parent->defObj->getEsdlType()==EsdlTypeArray)
|
|
|
+ {
|
|
|
+ JNIenv->CallObjectMethod(parent->obj, parent->append, entry->obj);
|
|
|
+ }
|
|
|
+ else if (parent->Class)
|
|
|
+ {
|
|
|
+ VStringBuffer javaSig("L%s;", javaClassName.str());
|
|
|
+ entry->fieldId = JNIenv->GetFieldID(parent->Class, fieldname, javaSig);
|
|
|
+ if (parent->obj && entry->fieldId)
|
|
|
+ JNIenv->SetObjectField(parent->obj, entry->fieldId, entry->obj);
|
|
|
+ }
|
|
|
+ javaembed::checkException(JNIenv, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ defStack.append(*entry.getClear());
|
|
|
+ }
|
|
|
+
|
|
|
+ IArrayOf<DefStackEntry> defStack;
|
|
|
+ MapStringTo<jclass> javaClasses;
|
|
|
+};
|
|
|
+
|
|
|
// Each call to a Java function will use a new JavaEmbedScriptContext object
|
|
|
#define MAX_JNI_ARGS 10
|
|
|
|
|
|
class JavaEmbedImportContext : public CInterfaceOf<IEmbedFunctionContext>
|
|
|
{
|
|
|
public:
|
|
|
- JavaEmbedImportContext(JavaThreadContext *_sharedCtx, const char *options)
|
|
|
- : sharedCtx(_sharedCtx)
|
|
|
+ JavaEmbedImportContext(JavaThreadContext *_sharedCtx, jobject _instance, const char *options)
|
|
|
+ : sharedCtx(_sharedCtx), instance(_instance)
|
|
|
{
|
|
|
argcount = 0;
|
|
|
argsig = NULL;
|
|
@@ -2134,6 +2824,29 @@ public:
|
|
|
v.l = javaBuilder.getObject();
|
|
|
addArg(v);
|
|
|
}
|
|
|
+ virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
|
|
|
+ {
|
|
|
+ if (*argsig != 'L') // should tell us the type of the object we need to create to pass in
|
|
|
+ typeError("OBJECT");
|
|
|
+ // Class name is from the char after the L up to the first ;
|
|
|
+ const char *tail = strchr(argsig, ';');
|
|
|
+ if (!tail)
|
|
|
+ typeError("OBJECT");
|
|
|
+ StringAttr className(argsig+1, tail - (argsig+1));
|
|
|
+ argsig = tail+1;
|
|
|
+ Owned<JavaXmlBuilder> writer = new JavaXmlBuilder(sharedCtx->JNIenv, dynamic_cast<IEsdlDefinition*>(esdl), esdlservice, esdltype);
|
|
|
+ writer->initWriter();
|
|
|
+ return (IXmlWriter*)writer.getClear();
|
|
|
+ }
|
|
|
+ virtual void paramWriterCommit(IInterface *writer)
|
|
|
+ {
|
|
|
+ JavaXmlBuilder *javaWriter = dynamic_cast<JavaXmlBuilder*>(writer);
|
|
|
+ if (!javaWriter)
|
|
|
+ throw MakeStringException(0, "javaembed: Invalid object writer for %s", sharedCtx->querySignature());
|
|
|
+ jvalue v;
|
|
|
+ v.l = javaWriter->getObject();
|
|
|
+ addArg(v);
|
|
|
+ }
|
|
|
virtual void bindDatasetParam(const char *name, IOutputMetaData & metaVal, IRowStream * val)
|
|
|
{
|
|
|
jvalue v;
|
|
@@ -2212,10 +2925,13 @@ public:
|
|
|
}
|
|
|
addArg(v);
|
|
|
}
|
|
|
-
|
|
|
+ virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
|
|
|
+ {
|
|
|
+ return sharedCtx->writeObjectResult(result.l, dynamic_cast<IEsdlDefinition*>(esdl), esdlservice, esdltype, dynamic_cast<IXmlWriter*>(writer));
|
|
|
+ }
|
|
|
virtual void importFunction(size32_t lenChars, const char *utf)
|
|
|
{
|
|
|
- sharedCtx->importFunction(lenChars, utf, classpath);
|
|
|
+ sharedCtx->importFunction(lenChars, utf, classpath, instance);
|
|
|
argsig = sharedCtx->querySignature();
|
|
|
assertex(*argsig == '(');
|
|
|
argsig++;
|
|
@@ -2224,7 +2940,10 @@ public:
|
|
|
{
|
|
|
if (*argsig != ')')
|
|
|
throw MakeStringException(0, "javaembed: Too few ECL parameters passed for Java signature %s", sharedCtx->querySignature());
|
|
|
- sharedCtx->callFunction(result, args);
|
|
|
+ if (instance)
|
|
|
+ sharedCtx->callFunction(result, args, instance);
|
|
|
+ else
|
|
|
+ sharedCtx->callFunction(result, args);
|
|
|
}
|
|
|
|
|
|
virtual void compileEmbeddedScript(size32_t lenChars, const char *script)
|
|
@@ -2236,6 +2955,7 @@ protected:
|
|
|
jvalue result;
|
|
|
StringAttr classpath;
|
|
|
IArrayOf<ECLDatasetIterator> iterators; // to make sure they get freed
|
|
|
+ jobject instance; //instance of service object to call methods on
|
|
|
private:
|
|
|
|
|
|
void typeError(const char *ECLtype) __attribute__((noreturn))
|
|
@@ -2313,6 +3033,77 @@ static JNIEnv *queryJNIEnv()
|
|
|
return queryContext()->JNIenv;
|
|
|
}
|
|
|
|
|
|
+class JavaEmbedServiceContext : public CInterfaceOf<IEmbedServiceContext>
|
|
|
+{
|
|
|
+public:
|
|
|
+ JavaEmbedServiceContext(JavaThreadContext *_sharedCtx, const char *service, const char *_options)
|
|
|
+ : sharedCtx(_sharedCtx), Class(0), options(_options), className(service)
|
|
|
+ {
|
|
|
+ StringArray opts;
|
|
|
+ opts.appendList(options, ",");
|
|
|
+ ForEachItemIn(idx, opts)
|
|
|
+ {
|
|
|
+ const char *opt = opts.item(idx);
|
|
|
+ const char *val = strchr(opt, '=');
|
|
|
+ if (val)
|
|
|
+ {
|
|
|
+ StringBuffer optName(val-opt, opt);
|
|
|
+ val++;
|
|
|
+ if (stricmp(optName, "classpath")==0)
|
|
|
+ classpath.set(val);
|
|
|
+ else
|
|
|
+ throw MakeStringException(0, "javaembed: Unknown option %s", optName.str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create a new frame for local references and increase the capacity
|
|
|
+ // of those references to 64 (default is 16)
|
|
|
+ sharedCtx->JNIenv->PushLocalFrame(64);
|
|
|
+ }
|
|
|
+ ~JavaEmbedServiceContext()
|
|
|
+ {
|
|
|
+ sharedCtx->JNIenv->DeleteGlobalRef(object);
|
|
|
+ sharedCtx->JNIenv->DeleteGlobalRef(Class);
|
|
|
+ // Pop local reference frame; explicitly frees all local
|
|
|
+ // references made during that frame's lifetime
|
|
|
+ sharedCtx->JNIenv->PopLocalFrame(NULL);
|
|
|
+ }
|
|
|
+ void init()
|
|
|
+ {
|
|
|
+ jobject classLoader = sharedCtx->getThreadClassLoader();
|
|
|
+ checkException();
|
|
|
+ jmethodID loadClassMethod = sharedCtx->JNIenv->GetMethodID(sharedCtx->JNIenv->GetObjectClass(classLoader), "loadClass","(Ljava/lang/String;)Ljava/lang/Class;");
|
|
|
+ checkException();
|
|
|
+ jstring methodString = sharedCtx->JNIenv->NewStringUTF(className);
|
|
|
+ checkException();
|
|
|
+ Class = (jclass) sharedCtx->JNIenv->NewGlobalRef(sharedCtx->JNIenv->CallObjectMethod(classLoader, loadClassMethod, methodString));
|
|
|
+ checkException();
|
|
|
+
|
|
|
+ jmethodID constructor = sharedCtx->JNIenv->GetMethodID(Class, "<init>", "()V");
|
|
|
+ checkException();
|
|
|
+ object = sharedCtx->JNIenv->NewGlobalRef(sharedCtx->JNIenv->NewObject(Class, constructor));
|
|
|
+ checkException();
|
|
|
+ }
|
|
|
+ virtual IEmbedFunctionContext *createFunctionContext(const char *function)
|
|
|
+ {
|
|
|
+ Owned<JavaEmbedImportContext> fctx = new JavaEmbedImportContext(queryContext(), object, options);
|
|
|
+ fctx->importFunction(rtlUtf8Length(strlen(function), function), function);
|
|
|
+ return fctx.getClear();
|
|
|
+ }
|
|
|
+ void checkException()
|
|
|
+ {
|
|
|
+ javaembed::checkException(sharedCtx->JNIenv, false);
|
|
|
+ }
|
|
|
+
|
|
|
+protected:
|
|
|
+ JavaThreadContext *sharedCtx;
|
|
|
+ StringBuffer className;
|
|
|
+ jclass Class;
|
|
|
+ jobject object;
|
|
|
+ StringAttr classpath;
|
|
|
+ StringAttr options;
|
|
|
+};
|
|
|
+
|
|
|
class JavaEmbedContext : public CInterfaceOf<IEmbedContext>
|
|
|
{
|
|
|
public:
|
|
@@ -2323,7 +3114,13 @@ public:
|
|
|
virtual IEmbedFunctionContext *createFunctionContextEx(ICodeContext * ctx, unsigned flags, const char *options)
|
|
|
{
|
|
|
assertex(flags & EFimport);
|
|
|
- return new JavaEmbedImportContext(queryContext(), options);
|
|
|
+ return new JavaEmbedImportContext(queryContext(), NULL, options);
|
|
|
+ }
|
|
|
+ virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
|
|
|
+ {
|
|
|
+ Owned<JavaEmbedServiceContext> serviceContext = new JavaEmbedServiceContext(queryContext(), service, options);
|
|
|
+ serviceContext->init();
|
|
|
+ return serviceContext.getClear();
|
|
|
}
|
|
|
};
|
|
|
|