Browse Source

HPCC-14246 Allow DynamicESDL service methods to be written in JAVA

Signed-off-by: Anthony Fishbeck <anthony.fishbeck@lexisnexis.com>
Anthony Fishbeck 9 năm trước cách đây
mục cha
commit
3a360d3d3e
34 tập tin đã thay đổi với 2275 bổ sung218 xóa
  1. 105 0
      esp/esdllib/esdl_def.cpp
  2. 30 3
      esp/esdllib/esdl_def.hpp
  3. 29 0
      esp/esdllib/esdl_def_helper.cpp
  4. 4 1
      esp/esdllib/esdl_def_helper.hpp
  5. 3 0
      esp/esdllib/esdl_transformer.hpp
  6. 6 102
      esp/esdllib/esdl_transformer2.cpp
  7. 6 26
      esp/esdllib/esdl_transformer2.ipp
  8. 3 0
      esp/services/esdl_svc_engine/CMakeLists.txt
  9. 274 54
      esp/services/esdl_svc_engine/esdl_binding.cpp
  10. 19 0
      esp/services/esdl_svc_engine/esdl_binding.hpp
  11. 1 0
      esp/services/ws_esdlconfig/CMakeLists.txt
  12. 2 0
      esp/xslt/CMakeLists.txt
  13. 212 0
      esp/xslt/esdl2java_srvbase.xslt
  14. 44 0
      esp/xslt/esdl2java_srvdummy.xslt
  15. 170 0
      esp/xslt/esdl2javaplugin.xslt
  16. 16 0
      initfiles/examples/EsdlExample/EsdlExampleService.java
  17. 37 0
      initfiles/examples/EsdlExample/ReadMeFirst.txt
  18. 3 0
      initfiles/examples/EsdlExample/RoxieEchoPersonInfo.ecl
  19. 5 0
      initfiles/examples/EsdlExample/esdl_binding.xml
  20. 74 0
      initfiles/examples/EsdlExample/esdl_example.esdl
  21. 27 0
      initfiles/examples/EsdlExample/javarequest.xml
  22. 27 0
      initfiles/examples/EsdlExample/roxierequest.xml
  23. 15 0
      plugins/Rembed/Rembed.cpp
  24. 15 0
      plugins/cassandra/cassandraembed.cpp
  25. 2 0
      plugins/javaembed/CMakeLists.txt
  26. 807 10
      plugins/javaembed/javaembed.cpp
  27. 15 0
      plugins/mysql/mysqlembed.cpp
  28. 26 0
      plugins/pyembed/pyembed.cpp
  29. 14 0
      plugins/sqlite3/sqlite3.cpp
  30. 15 0
      plugins/v8embed/v8embed.cpp
  31. 9 0
      rtl/eclrtl/eclrtl.hpp
  32. 1 1
      tools/esdlcmd/esdl-publish.cpp
  33. 12 10
      tools/esdlcmd/esdlcmd_common.hpp
  34. 247 11
      tools/esdlcmd/esdlcmd_core.cpp

+ 105 - 0
esp/esdllib/esdl_def.cpp

@@ -1310,6 +1310,10 @@ public:
     bool hasFileLoaded(const char *filename);
     bool hasXMLDefintionLoaded(const char *esdlDefName, int ver);
     bool hasXMLDefintionLoaded(const char *esdlDefId);
+    EsdlBasicElementType translateSimpleType(const char *type)
+    {
+        return esdlSimpleType(type);
+    }
 
 
     IEsdlDefObject *queryObj(const char *name)
@@ -2085,3 +2089,104 @@ esdl_decl void releaseEsdlDefinition(const char *esdl_ns)
     else
         default_ns.clear();
 }
+
+static bool type_list_inited = false;
+
+typedef MapStringTo<EsdlBasicElementType> EsdlTypeList;
+static EsdlTypeList esdlTypeList;
+
+void init_type_list_v2(EsdlTypeList &list)
+{
+    static CriticalSection crit;
+    CriticalBlock block(crit);
+    if (!type_list_inited)
+    {
+        //strings:
+        list.setValue("StringBuffer", ESDLT_STRING);
+        list.setValue("string", ESDLT_STRING);
+        list.setValue("binary", ESDLT_STRING);
+        list.setValue("base64Binary", ESDLT_STRING);
+        list.setValue("normalizedString", ESDLT_STRING);
+        list.setValue("xsdString", ESDLT_STRING);
+        list.setValue("xsdBinary", ESDLT_STRING);
+        list.setValue("xsdDuration", ESDLT_STRING);
+        list.setValue("xsdDateTime", ESDLT_STRING);
+        list.setValue("xsdTime", ESDLT_STRING);
+        list.setValue("xsdDate", ESDLT_STRING);
+        list.setValue("xsdYearMonth", ESDLT_STRING);
+        list.setValue("xsdYear", ESDLT_STRING);
+        list.setValue("xsdMonthDay", ESDLT_STRING);
+        list.setValue("xsdDay", ESDLT_STRING);
+        list.setValue("xsdMonth", ESDLT_STRING);
+        list.setValue("xsdAnyURI", ESDLT_STRING);
+        list.setValue("xsdQName", ESDLT_STRING);
+        list.setValue("xsdNOTATION", ESDLT_STRING);
+        list.setValue("xsdToken", ESDLT_STRING);
+        list.setValue("xsdLanguage", ESDLT_STRING);
+        list.setValue("xsdNMTOKEN", ESDLT_STRING);
+        list.setValue("xsdNMTOKENS", ESDLT_STRING);
+        list.setValue("xsdName", ESDLT_STRING);
+        list.setValue("xsdNCName", ESDLT_STRING);
+        list.setValue("xsdID", ESDLT_STRING);
+        list.setValue("xsdIDREF", ESDLT_STRING);
+        list.setValue("xsdIDREFS", ESDLT_STRING);
+        list.setValue("xsdENTITY", ESDLT_STRING);
+        list.setValue("xsdENTITIES", ESDLT_STRING);
+        list.setValue("xsdBase64Binary", ESDLT_STRING);
+        list.setValue("xsdNormalizedString", ESDLT_STRING);
+        list.setValue("EspTextFile", ESDLT_STRING);
+        list.setValue("EspResultSet", ESDLT_STRING);
+        //numeric
+        list.setValue("bool", ESDLT_BOOL);
+        list.setValue("boolean", ESDLT_BOOL);
+        list.setValue("decimal", ESDLT_FLOAT);
+        list.setValue("float", ESDLT_FLOAT);
+        list.setValue("double", ESDLT_DOUBLE);
+        list.setValue("integer", ESDLT_INT32);
+        list.setValue("int64", ESDLT_INT64);
+        list.setValue("long", ESDLT_INT32);
+        list.setValue("int", ESDLT_INT32);
+        list.setValue("unsigned", ESDLT_UINT32);
+        list.setValue("short", ESDLT_INT16);
+        list.setValue("nonPositiveInteger", ESDLT_INT32);
+        list.setValue("negativeInteger", ESDLT_INT32);
+        list.setValue("nonNegativeInteger", ESDLT_UINT32);
+        list.setValue("unsignedLong", ESDLT_UINT32);
+        list.setValue("unsignedInt", ESDLT_UINT32);
+        list.setValue("unsignedShort", ESDLT_UINT16);
+        list.setValue("unsignedByte", ESDLT_UBYTE);
+        list.setValue("positiveInteger", ESDLT_UINT32);
+        list.setValue("xsdBoolean", ESDLT_BOOL);
+        list.setValue("xsdDecimal", ESDLT_FLOAT);
+        list.setValue("xsdInteger", ESDLT_INT32);
+        list.setValue("xsdByte", ESDLT_INT8);
+        list.setValue("xsdNonPositiveInteger", ESDLT_INT32);
+        list.setValue("xsdNegativeInteger", ESDLT_INT32);
+        list.setValue("xsdNonNegativeInteger", ESDLT_UINT32);
+        list.setValue("xsdUnsignedLong", ESDLT_UINT32);
+        list.setValue("xsdUnsignedInt", ESDLT_UINT32);
+        list.setValue("xsdUnsignedShort", ESDLT_UINT16);
+        list.setValue("xsdUnsignedByte", ESDLT_UINT8);
+        list.setValue("xsdPositiveInteger", ESDLT_UINT64);
+        list.setValue("unsigned8", ESDLT_UINT64);
+
+        type_list_inited=true;
+    }
+}
+
+esdl_decl void initEsdlTypeList()
+{
+    if (!type_list_inited)
+        init_type_list_v2(esdlTypeList);
+}
+
+esdl_decl EsdlBasicElementType esdlSimpleType(const char *type)
+{
+    if (!type || !*type)
+        return ESDLT_STRING;
+    initEsdlTypeList();
+    EsdlBasicElementType *val = esdlTypeList.getValue(type);
+    if (val)
+        return *val;
+    return ESDLT_COMPLEX;
+}

+ 30 - 3
esp/esdllib/esdl_def.hpp

@@ -19,9 +19,9 @@
 #define ESDLDEF_HPP
 
 #include "jliball.hpp"
-#include "esp.hpp"
-#include "soapesp.hpp"
-#include "ws_ecl_client.hpp"
+//#include "esp.hpp"
+//#include "soapesp.hpp"
+//#include "ws_ecl_client.hpp"
 #include "jqueue.tpp"
 
 #ifdef _WIN32
@@ -34,6 +34,29 @@
  #define esdl_decl
 #endif
 
+typedef enum
+{
+    ESDLT_UNKOWN,
+    ESDLT_STRUCT,
+    ESDLT_REQUEST,
+    ESDLT_RESPONSE,
+    ESDLT_COMPLEX,
+    ESDLT_STRING,
+    ESDLT_INT8,
+    ESDLT_INT16,
+    ESDLT_INT32,
+    ESDLT_INT64,
+    ESDLT_UINT8,
+    ESDLT_UINT16,
+    ESDLT_UINT32,
+    ESDLT_UINT64,
+    ESDLT_BOOL,
+    ESDLT_FLOAT,
+    ESDLT_DOUBLE,
+    ESDLT_BYTE,
+    ESDLT_UBYTE
+} EsdlBasicElementType;
+
 typedef enum EsdlDefTypeId_
 {
     EsdlTypeElement,
@@ -189,6 +212,7 @@ interface IEsdlDefinition : extends IInterface
     virtual bool hasFileLoaded(const char *filename)=0;
     virtual bool hasXMLDefintionLoaded(const char *esdlDefName, int ver)=0;
     virtual bool hasXMLDefintionLoaded(const char *esdlDefId)=0;
+    virtual EsdlBasicElementType translateSimpleType(const char *type)=0;
 };
 
 esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns=NULL);
@@ -196,5 +220,8 @@ esdl_decl IEsdlDefinition *createEsdlDefinition(const char *esdl_ns=NULL);
 esdl_decl IEsdlDefinition *queryEsdlDefinition(const char *esdl_ns=NULL);
 esdl_decl void releaseEsdlDefinition(const char *esdl_ns=NULL);
 
+esdl_decl void initEsdlTypeList();
+esdl_decl EsdlBasicElementType esdlSimpleType(const char *type);
+
 
 #endif //ESDLDEF_HPP

+ 29 - 0
esp/esdllib/esdl_def_helper.cpp

@@ -72,6 +72,7 @@ public:
     virtual void toXSD( IEsdlDefObjectIterator &objs, StringBuffer &xsd, EsdlXslTypeId xslId, double version, IProperties *opts, const char *ns=NULL, unsigned flags=0 );
     virtual void toXSD( IEsdlDefObjectIterator &objs, StringBuffer &xsd, StringBuffer &xslt, double version, IProperties *opts, const char *ns=NULL, unsigned flags=0 );
     virtual void toWSDL( IEsdlDefObjectIterator &objs, StringBuffer &xsd, EsdlXslTypeId xslId, double version, IProperties *opts, const char *ns=NULL, unsigned flags=0 );
+    virtual void toJavaService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId classType, IProperties *opts, unsigned flags);
 
     void loadTransformParams( EsdlXslTypeId xslId );
 
@@ -256,6 +257,34 @@ void EsdlDefinitionHelper::loadTransformParams( EsdlXslTypeId xslId)
     }
 }
 
+void EsdlDefinitionHelper::toJavaService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId implType, IProperties *opts, unsigned flags)
+{
+    StringBuffer xml;
+    int xmlLen = 0;
+    IXslTransform* trans = *( transforms.getValue( implType ) );
+
+    this->loadTransformParams( implType );
+
+    if( trans )
+    {
+        IProperties* params = *( parameters.getValue(implType) );
+
+        xml.appendf("<esxdl name='custom' EsdlXslTypeId='%d' xmlns:tns='%s' ns_uri='%s' version='0'>", implType, "urn:unknown", "urn:unknown");
+        this->toXML( objs, xml, 0, opts, flags );
+        xml.append("</esxdl>");
+
+        trans->setXmlSource( xml.str(), xml.length() );
+        trans->transform(content);
+        //content.append(xml);
+    }
+    else
+    {
+        throw (MakeStringExceptionDirect( 0, "Unable to find transform for creating java service plugin"));
+    }
+
+    return;
+}
+
 esdl_decl IEsdlDefinitionHelper* createEsdlDefinitionHelper( )
 {
     return new EsdlDefinitionHelper( );

+ 4 - 1
esp/esdllib/esdl_def_helper.hpp

@@ -30,7 +30,9 @@
 typedef enum EsdlXslTypeId_
 {
     EsdlXslToXsd,
-    EsdlXslToWsdl
+    EsdlXslToWsdl,
+    EsdlXslToJavaServiceBase,
+    EsdlXslToJavaServiceDummy
 } EsdlXslTypeId;
 
 interface IEsdlDefinitionHelper : extends IInterface
@@ -42,6 +44,7 @@ interface IEsdlDefinitionHelper : extends IInterface
     virtual void toXSD( IEsdlDefObjectIterator& objs, StringBuffer &xsd, EsdlXslTypeId xslId, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )=0;
     virtual void toXSD( IEsdlDefObjectIterator& objs, StringBuffer &xsd, StringBuffer& xslt, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )=0;
     virtual void toWSDL( IEsdlDefObjectIterator& objs, StringBuffer &wsdl, EsdlXslTypeId xslId, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )=0;
+    virtual void toJavaService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId implType, IProperties *opts=NULL, unsigned flags=0 )=0;
 };
 
 

+ 3 - 0
esp/esdllib/esdl_transformer.hpp

@@ -18,6 +18,9 @@
 #ifndef __ESDL_TRANSFORMER_HPP__
 #define __ESDL_TRANSFORMER_HPP__
 
+#include "esp.hpp"
+#include "soapesp.hpp"
+#include "ws_ecl_client.hpp"
 #include "esdl_def.hpp"
 
 typedef  enum EsdlProcessMode_

+ 6 - 102
esp/esdllib/esdl_transformer2.cpp

@@ -60,101 +60,6 @@ using namespace xpp;
 // ======================================================================================
 // primitive type lookup
 
-typedef MapStringTo<Esdl2Type> EsdlTypeList;
-
-static bool type_list_inited = false;
-static EsdlTypeList TypeList;
-
-void init_type_list_v2(EsdlTypeList &list)
-{
-    static CriticalSection crit;
-    CriticalBlock block(crit);
-    if (!type_list_inited)
-    {
-        //strings:
-        list.setValue("StringBuffer", ESDLT_STRING);
-        list.setValue("string", ESDLT_STRING);
-        list.setValue("binary", ESDLT_STRING);
-        list.setValue("base64Binary", ESDLT_STRING);
-        list.setValue("normalizedString", ESDLT_STRING);
-        list.setValue("xsdString", ESDLT_STRING);
-        list.setValue("xsdBinary", ESDLT_STRING);
-        list.setValue("xsdDuration", ESDLT_STRING);
-        list.setValue("xsdDateTime", ESDLT_STRING);
-        list.setValue("xsdTime", ESDLT_STRING);
-        list.setValue("xsdDate", ESDLT_STRING);
-        list.setValue("xsdYearMonth", ESDLT_STRING);
-        list.setValue("xsdYear", ESDLT_STRING);
-        list.setValue("xsdMonthDay", ESDLT_STRING);
-        list.setValue("xsdDay", ESDLT_STRING);
-        list.setValue("xsdMonth", ESDLT_STRING);
-        list.setValue("xsdAnyURI", ESDLT_STRING);
-        list.setValue("xsdQName", ESDLT_STRING);
-        list.setValue("xsdNOTATION", ESDLT_STRING);
-        list.setValue("xsdToken", ESDLT_STRING);
-        list.setValue("xsdLanguage", ESDLT_STRING);
-        list.setValue("xsdNMTOKEN", ESDLT_STRING);
-        list.setValue("xsdNMTOKENS", ESDLT_STRING);
-        list.setValue("xsdName", ESDLT_STRING);
-        list.setValue("xsdNCName", ESDLT_STRING);
-        list.setValue("xsdID", ESDLT_STRING);
-        list.setValue("xsdIDREF", ESDLT_STRING);
-        list.setValue("xsdIDREFS", ESDLT_STRING);
-        list.setValue("xsdENTITY", ESDLT_STRING);
-        list.setValue("xsdENTITIES", ESDLT_STRING);
-        list.setValue("xsdBase64Binary", ESDLT_STRING);
-        list.setValue("xsdNormalizedString", ESDLT_STRING);
-        list.setValue("EspTextFile", ESDLT_STRING);
-        list.setValue("EspResultSet", ESDLT_STRING);
-        //numeric
-        list.setValue("bool", ESDLT_BOOL);
-        list.setValue("boolean", ESDLT_BOOL);
-        list.setValue("decimal", ESDLT_FLOAT);
-        list.setValue("float", ESDLT_FLOAT);
-        list.setValue("double", ESDLT_DOUBLE);
-        list.setValue("integer", ESDLT_INT32);
-        list.setValue("int64", ESDLT_INT64);
-        list.setValue("long", ESDLT_INT32);
-        list.setValue("int", ESDLT_INT32);
-        list.setValue("unsigned", ESDLT_UINT32);
-        list.setValue("short", ESDLT_INT16);
-        list.setValue("nonPositiveInteger", ESDLT_INT32);
-        list.setValue("negativeInteger", ESDLT_INT32);
-        list.setValue("nonNegativeInteger", ESDLT_UINT32);
-        list.setValue("unsignedLong", ESDLT_UINT32);
-        list.setValue("unsignedInt", ESDLT_UINT32);
-        list.setValue("unsignedShort", ESDLT_UINT16);
-        list.setValue("unsignedByte", ESDLT_UBYTE);
-        list.setValue("positiveInteger", ESDLT_UINT32);
-        list.setValue("xsdBoolean", ESDLT_BOOL);
-        list.setValue("xsdDecimal", ESDLT_FLOAT);
-        list.setValue("xsdInteger", ESDLT_INT32);
-        list.setValue("xsdByte", ESDLT_INT8);
-        list.setValue("xsdNonPositiveInteger", ESDLT_INT32);
-        list.setValue("xsdNegativeInteger", ESDLT_INT32);
-        list.setValue("xsdNonNegativeInteger", ESDLT_UINT32);
-        list.setValue("xsdUnsignedLong", ESDLT_UINT32);
-        list.setValue("xsdUnsignedInt", ESDLT_UINT32);
-        list.setValue("xsdUnsignedShort", ESDLT_UINT16);
-        list.setValue("xsdUnsignedByte", ESDLT_UINT8);
-        list.setValue("xsdPositiveInteger", ESDLT_UINT64);
-        list.setValue("unsigned8", ESDLT_UINT64);
-
-        type_list_inited=true;
-    }
-}
-
-static Esdl2Type simpleType(const char *type)
-{
-    if (!type || !*type)
-        return ESDLT_STRING;
-
-    Esdl2Type *val = TypeList.getValue(type);
-    if (val)
-        return *val;
-    return ESDLT_COMPLEX;
-}
-
 static bool gotoStartTag(XmlPullParser &xppx, const char *name, const char *dsname)
 {
     int level = 1;
@@ -264,7 +169,7 @@ void Esdl2LocalContext::handleDataFor(IXmlWriterExt & writer)
 // ======================================================================================
 // class Esdl2Base
 
-Esdl2Base::Esdl2Base(Esdl2Transformer *xformer, IEsdlDefObject* def, Esdl2Type t, bool might_skip_root_)
+Esdl2Base::Esdl2Base(Esdl2Transformer *xformer, IEsdlDefObject* def, EsdlBasicElementType t, bool might_skip_root_)
 : m_def(def), might_skip_root(might_skip_root_), data_for(NULL), type_id(t)
 {
     if (def->queryProp("optional"))
@@ -542,7 +447,7 @@ Esdl2Base* Esdl2Base::queryChild(const char* name, bool nocase)
 
 void Esdl2Base::mergeBaseType(Esdl2Transformer *xformer, const char *base_type)
 {
-    if (simpleType(base_type)==ESDLT_COMPLEX)
+    if (esdlSimpleType(base_type)==ESDLT_COMPLEX)
     {
         Esdl2Base *esdlBase = xformer->queryType(base_type);
 
@@ -578,7 +483,7 @@ Esdl2Element::Esdl2Element(Esdl2Transformer *xformer, IEsdlDefObject *def) : Esd
     simple_type.set(def->queryProp("type"));
     if (!simple_type.isEmpty())
     {
-        type_id = simpleType(simple_type.get());
+        type_id = esdlSimpleType(simple_type.get());
         if (type_id==ESDLT_COMPLEX)
         {
             DBGLOG("ESDL simple type not defined: %s", simple_type.get());
@@ -728,7 +633,7 @@ Esdl2Array::Esdl2Array(Esdl2Transformer *xformer, IEsdlDefObject *def) : Esdl2Ba
     if (atype)
     {
         type.set(atype);
-        type_id = simpleType(atype);
+        type_id = esdlSimpleType(atype);
     }
 
     const char* itag = def->queryProp("item_tag");
@@ -911,7 +816,7 @@ void Esdl2Array::process(Esdl2TransformerContext &ctx, const char *out_name, Esd
 // ======================================================================================
 // class Esdl2Struct
 
-Esdl2Struct::Esdl2Struct(Esdl2Transformer *xformer, IEsdlDefStruct *def, Esdl2Type t)
+Esdl2Struct::Esdl2Struct(Esdl2Transformer *xformer, IEsdlDefStruct *def, EsdlBasicElementType t)
  : Esdl2Base(xformer, def, t, t==ESDLT_RESPONSE),isElement(false)
 {
     ESDL_DBG("Esdl2Struct: %s", def->queryName());
@@ -1425,8 +1330,7 @@ void Esdl2EnumRef::process(Esdl2TransformerContext &ctx, const char *out_name, E
 Esdl2Transformer::Esdl2Transformer(IEsdlDefinition* def)
 {
     m_def.setown(LINK(def));
-    if (!type_list_inited)
-        init_type_list_v2(TypeList);
+    initEsdlTypeList();
 }
 
 void Esdl2Transformer::serialize(StringBuffer &out)

+ 6 - 26
esp/esdllib/esdl_transformer2.ipp

@@ -25,6 +25,9 @@
 #include "esdl_transformer.hpp"
 #include <xpp/XmlPullParser.h>
 #include <map>
+#include "esp.hpp"
+#include "soapesp.hpp"
+#include "ws_ecl_client.hpp"
 #include "esdl_def.hpp"
 #include "eclhelper.hpp"
 
@@ -42,29 +45,6 @@ typedef MapStringTo<IPTreePtr> AddedList;
 
 // ======================================================================================
 
-typedef enum
-{
-    ESDLT_UNKOWN,
-    ESDLT_STRUCT,
-    ESDLT_REQUEST,
-    ESDLT_RESPONSE,
-    ESDLT_COMPLEX,
-    ESDLT_STRING,
-    ESDLT_INT8,
-    ESDLT_INT16,
-    ESDLT_INT32,
-    ESDLT_INT64,
-    ESDLT_UINT8,
-    ESDLT_UINT16,
-    ESDLT_UINT32,
-    ESDLT_UINT64,
-    ESDLT_BOOL,
-    ESDLT_FLOAT,
-    ESDLT_DOUBLE,
-    ESDLT_BYTE,
-    ESDLT_UBYTE
-} Esdl2Type;
-
 // ======================================================================================
 // Context for ESDL transformer
 
@@ -149,7 +129,7 @@ class Esdl2Base : public CInterface
 {
 protected:
     IEsdlDefObject* m_def;
-    Esdl2Type type_id;
+    EsdlBasicElementType type_id;
 
     StringAttr xml_tag;
     StringAttr param_group;
@@ -164,7 +144,7 @@ protected:
 public:
     IMPLEMENT_IINTERFACE;
 
-    Esdl2Base(Esdl2Transformer *xformer, IEsdlDefObject* def, Esdl2Type t=ESDLT_UNKOWN, bool might_skip_root_=false);
+    Esdl2Base(Esdl2Transformer *xformer, IEsdlDefObject* def, EsdlBasicElementType t=ESDLT_UNKOWN, bool might_skip_root_=false);
     virtual ~Esdl2Base();
 
     virtual bool hasChild() { return false; }
@@ -358,7 +338,7 @@ private:
     EsdlBaseMap   m_child_map;
 
 public:
-    Esdl2Struct(Esdl2Transformer *xformer, IEsdlDefStruct *def, Esdl2Type t=ESDLT_STRUCT);
+    Esdl2Struct(Esdl2Transformer *xformer, IEsdlDefStruct *def, EsdlBasicElementType t=ESDLT_STRUCT);
     virtual ~Esdl2Struct();
 
     virtual bool hasChild() { return !m_children.empty(); }

+ 3 - 0
esp/services/esdl_svc_engine/CMakeLists.txt

@@ -49,7 +49,10 @@ include_directories (
          ${HPCC_SOURCE_DIR}/common/deftype
          ${HPCC_SOURCE_DIR}/common/environment
          ${HPCC_SOURCE_DIR}/common/thorhelper
+         ${HPCC_SOURCE_DIR}/common/workunit
+         ${HPCC_SOURCE_DIR}/common/wuwebview
          ${HPCC_SOURCE_DIR}/ecl/hql
+         ${HPCC_SOURCE_DIR}/rtl/eclrtl
          ${HPCC_SOURCE_DIR}/rtl/include
          ${HPCC_SOURCE_DIR}/esp/esdllib
          ${HPCC_SOURCE_DIR}/esp/logging

+ 274 - 54
esp/services/esdl_svc_engine/esdl_binding.cpp

@@ -31,6 +31,8 @@
 #include "jsonhelpers.hpp"
 #include "eclhelper.hpp"    //IXMLWriter
 #include "thorxmlwrite.hpp" //JSON WRITER
+#include "workunit.hpp"
+#include "wuwebview.hpp"
 
 /*
  * trim xpath at first instance of element
@@ -195,6 +197,7 @@ bool EsdlServiceImpl::loadLogggingManager()
     return true;
 }
 
+
 void EsdlServiceImpl::init(const IPropertyTree *cfg,
                            const char *process,
                            const char *service)
@@ -229,6 +232,63 @@ void EsdlServiceImpl::init(const IPropertyTree *cfg,
         throw MakeStringException(-1, "Could not access ESDL service configuration: esp process '%s' service name '%s'", process, service);
 }
 
+void EsdlServiceImpl::configureJavaMethod(const char *method, IPropertyTree &entry)
+{
+    const char *javaScopedMethod = entry.queryProp("@javamethod");
+    if (!javaScopedMethod || !*javaScopedMethod)
+    {
+        DBGLOG("ESDL binding - found java target method \"%s\" without java method defined.", method);
+        return;
+    }
+
+    StringArray javaNodes;
+    javaNodes.appendList(javaScopedMethod, ".");
+    if (javaNodes.length()!=3) //adf: may become more flexible?
+    {
+        DBGLOG("ESDL binding - target method \"%s\", configured java method currently must be of the form 'package.class.method', found (%s).", method, javaScopedMethod);
+        return;
+    }
+
+    const char *javaPackage = javaNodes.item(0);
+    const char *javaClass = javaNodes.item(1);
+    const char *javaMethod = javaNodes.item(2);
+
+    VStringBuffer javaScopedClass("%s.%s", javaPackage, javaClass);
+    entry.setProp("@javaclass", javaScopedClass);
+
+    if (!javaServiceMap.getValue(javaScopedClass))
+    {
+        Owned<IEmbedServiceContext> srvctx = ensureJavaEmbeded().createServiceContext(javaScopedClass, EFimport, "classpath=/opt/HPCCSystems/classes");
+        javaServiceMap.setValue(javaScopedClass, srvctx.getClear());
+    }
+}
+
+void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entry)
+{
+    const char *url = entry.queryProp("@url");
+    if (!url || !*url)
+    {
+        DBGLOG("ESDL binding - found target method \"%s\" without target url!", method);
+        return;
+    }
+
+    if (!entry.hasProp("@queryname"))
+    {
+        DBGLOG("ESDL binding - found target method \"%s\" without target query!", method);
+        return;
+    }
+
+    StringBuffer protocol, name, pw, path, iplist, ops;
+    EsdlBindingImpl::splitURLList(url, protocol, name, pw, iplist, path, ops);
+
+    entry.setProp("@prot", protocol);
+    entry.setProp("@path", path);
+
+    Owned<ISmartSocketFactory> sf = createSmartSocketFactory(iplist, true);
+    connMap.remove(method);
+    connMap.setValue(method, sf.getClear());
+}
+
 void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
 {
     StringBuffer lc(service);
@@ -247,35 +307,16 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
             m_pServiceMethodTargets->addPropTree("Target", createPTreeFromIPT(&itns->query()));
 
         Owned<IPropertyTreeIterator> iter = m_pServiceMethodTargets->getElements("Target");
-        StringBuffer targetname;
-        StringBuffer targeturl;
         ForEach(*iter)
         {
-            iter->query().getProp("@name", targetname.clear());
-            if (targetname.length() > 0)
-            {
-                if (!iter->query().hasProp("@queryname"))
-                {
-                    DBGLOG("ESDL binding - found target method \"%s\" without target query!", targetname.str());
-                    continue;
-                }
-
-                iter->query().getProp("@url", targeturl.clear());
-
-                StringBuffer protocol, name, pw, path, iplist, ops;
-                EsdlBindingImpl::splitURLList(targeturl.str(),protocol,name,pw,iplist,path,ops);
-
-                iter->query().setProp("@prot", protocol.str());
-                iter->query().setProp("@path", path.str());
-
-                Owned<ISmartSocketFactory> sf = createSmartSocketFactory(iplist.str(), true);
-                connMap.remove(targetname.str());
-                connMap.setValue(targetname.str(), sf.get());
-            }
-            else
-            {
+            const char *method = iter->query().queryProp("@name");
+            if (!method || !*method)
                 throw MakeStringException(-1, "ESDL binding - found target method entry without name!");
-            }
+            const char *type = iter->query().queryProp("@querytype");
+            if (type && strieq(type, "java"))
+                configureJavaMethod(method, iter->query());
+            else
+                configureUrlMethod(method, iter->query());
         }
     }
     else
@@ -286,6 +327,36 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
 #define ESDLREQ_FLAGS (ESDL_TRANS_START_AT_ROOT | ESDL_TRANS_TRIM | ESDL_TRANS_OUTPUT_XMLTAG)
 #define ESDLDEP_FLAGS (DEPFLAG_COLLAPSE | DEPFLAG_ARRAYOF)
 
+enum EsdlMethodImplType
+{
+    EsdlMethodImplUnknown,
+    EsdlMethodImplRoxie,
+    EsdlMethodImplWsEcl,
+    EsdlMethodImplProxy,
+    EsdlMethodImplJava
+};
+
+inline EsdlMethodImplType getEsdlMethodImplType(const char *querytype)
+{
+    if (querytype)
+    {
+        if (strieq(querytype, "roxie"))
+            return EsdlMethodImplRoxie;
+        if (strieq(querytype, "wsecl"))
+            return EsdlMethodImplWsEcl;
+        if (strieq(querytype, "proxy"))
+            return EsdlMethodImplProxy;
+        if (strieq(querytype, "java"))
+            return EsdlMethodImplJava;
+    }
+    return EsdlMethodImplRoxie;
+}
+
+static inline bool isPublishedQuery(EsdlMethodImplType implType)
+{
+    return (implType==EsdlMethodImplRoxie || implType==EsdlMethodImplWsEcl);
+}
+
 void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
                                            IEsdlDefService &srvdef,
                                            IEsdlDefMethod &mthdef,
@@ -301,9 +372,8 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
     const char *mthName = mthdef.queryName();
     context.addTraceSummaryValue("method", mthName);
 
-    StringBuffer soapresp;
-    bool isroxie = false;
-    bool isproxy = false;
+    StringBuffer origResp;
+    EsdlMethodImplType implType = EsdlMethodImplUnknown;
 
     if(stricmp(mthName, "echotest")==0 || mthdef.hasProp("EchoTest"))
     {
@@ -313,45 +383,86 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
     else
     {
         if (!m_pServiceMethodTargets)
-            throw makeWsException( ERR_ESDL_BINDING_INTERNERR, WSERR_CLIENT, "ESP", "Service methods not configured!");
+            throw makeWsException( ERR_ESDL_BINDING_INTERNERR, WSERR_CLIENT, "ESDL", "Service methods not configured!");
 
         VStringBuffer xpath("Target[@name=\"%s\"]", mthName);
         tgtcfg.setown(m_pServiceMethodTargets->getPropTree(xpath.str()));
 
         if (!tgtcfg)
-            throw makeWsException( ERR_ESDL_BINDING_BADREQUEST, WSERR_CLIENT, "ESP", "Target not configured for method: %s", mthName );
+            throw makeWsException( ERR_ESDL_BINDING_BADREQUEST, WSERR_CLIENT, "ESDL", "Target not configured for method: %s", mthName );
 
-        const char *querytype = tgtcfg->queryProp("@querytype");
-        isroxie = querytype && (strnicmp(querytype, "roxie", 5)==0 || strnicmp(querytype, "wsecl", 5)==0);
-        isproxy = (querytype && strnicmp(querytype, "proxy", 5)==0);
+        implType = getEsdlMethodImplType(tgtcfg->queryProp("@querytype"));
 
-        Owned<IXmlWriterExt> reqWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
+        if (implType==EsdlMethodImplJava)
+        {
+            const char *javaPackage = srvdef.queryName();
+            const char *javaScopedClass = tgtcfg->queryProp("@javaclass");
+            const char *javaScopedMethod = tgtcfg->queryProp("@javamethod");
+
+            Linked<IEmbedServiceContext> srvctx = javaServiceMap.getValue(javaScopedClass);
+            if (!srvctx)
+                throw makeWsException(ERR_ESDL_BINDING_BADREQUEST, WSERR_SERVER, "ESDL", "Java class %s not loaded for method %s", javaScopedClass, mthName);
+
+            //"WsWorkunits.WsWorkunitsService.WUAbort:(LWsWorkunits/EsdlContext;LWsWorkunits/WUAbortRequest;)LWsWorkunits/WUAbortResponse;";
+            VStringBuffer signature("%s:(L%s/EsdlContext;L%s/%s;)L%s/%s;", javaScopedMethod, javaPackage, javaPackage, mthdef.queryRequestType(), javaPackage, mthdef.queryResponseType());
+
+            Owned<IEmbedFunctionContext> javactx;
+            javactx.setown(srvctx->createFunctionContext(signature));
+            if (!javactx)
+                throw makeWsException(ERR_ESDL_BINDING_BADREQUEST, WSERR_SERVER, "ESDL", "Java method %s could not be loaded from class %s in esdl method %s", tgtcfg->queryProp("@javamethod"), javaScopedClass, mthName);
+
+            Owned<IXmlWriterExt> writer = dynamic_cast<IXmlWriterExt *>(javactx->bindParamWriter(m_esdl, javaPackage, "EsdlContext", "context"));
+             if (writer)
+             {
+                if (context.queryUserId())
+                    writer->outputCString(context.queryUserId(), "username");
+                javactx->paramWriterCommit(writer);
+             }
+
+             writer.setown(dynamic_cast<IXmlWriterExt *>(javactx->bindParamWriter(m_esdl, javaPackage, mthdef.queryRequestType(), "request")));
+             m_pEsdlTransformer->process(context, EsdlRequestMode, srvdef.queryName(), mthdef.queryName(), *req, writer, 0, NULL);
+             javactx->paramWriterCommit(writer);
+             javactx->callFunction();
+
+             Owned<IXmlWriterExt> javaRespWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
+             javactx->writeResult(m_esdl, srvdef.queryName(), mthdef.queryResponseType(), javaRespWriter);
+             origResp.set(javaRespWriter->str());
+
+             Owned<IXmlWriterExt> finalRespWriter = createIXmlWriterExt(0, 0, NULL, (flags & ESDL_BINDING_RESPONSE_JSON) ? WTJSON : WTStandard);
+             m_pEsdlTransformer->processHPCCResult(context, mthdef, origResp.str(), finalRespWriter, logdata, ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
+
+             out.append(finalRespWriter->str());
+        }
+        else
+        {
+            Owned<IXmlWriterExt> reqWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
 
-        //Preprocess Request
-        StringBuffer reqcontent;
-        unsigned xflags = (isroxie) ? ROXIEREQ_FLAGS : ESDLREQ_FLAGS;
-        m_pEsdlTransformer->process(context, EsdlRequestMode, srvdef.queryName(), mthdef.queryName(), *req, reqWriter.get(), xflags, NULL);
+            //Preprocess Request
+            StringBuffer reqcontent;
+            unsigned xflags = (isPublishedQuery(implType)) ? ROXIEREQ_FLAGS : ESDLREQ_FLAGS;
+            m_pEsdlTransformer->process(context, EsdlRequestMode, srvdef.queryName(), mthdef.queryName(), *req, reqWriter.get(), xflags, NULL);
 
-        if(isroxie)
-            tgtctx.setown(createTargetContext(context, tgtcfg.get(), srvdef, mthdef, req));
+            if(isPublishedQuery(implType))
+                tgtctx.setown(createTargetContext(context, tgtcfg.get(), srvdef, mthdef, req));
 
-        reqcontent.set(reqWriter->str());
-        handleFinalRequest(context,tgtcfg,tgtctx,srvdef,mthdef,ns,reqcontent,soapresp,isroxie,isproxy);
-    }
+            reqcontent.set(reqWriter->str());
+            handleFinalRequest(context, tgtcfg, tgtctx, srvdef, mthdef, ns, reqcontent, origResp, isPublishedQuery(implType), implType==EsdlMethodImplProxy);
 
-    if (isroxie)
-    {
-        Owned<IXmlWriterExt> respWriter = createIXmlWriterExt(0, 0, NULL, (flags & ESDL_BINDING_RESPONSE_JSON) ? WTJSON : WTStandard);
-        m_pEsdlTransformer->processHPCCResult(context, mthdef, soapresp.str(), respWriter.get(), logdata, ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
+            if (isPublishedQuery(implType))
+            {
+                Owned<IXmlWriterExt> respWriter = createIXmlWriterExt(0, 0, NULL, (flags & ESDL_BINDING_RESPONSE_JSON) ? WTJSON : WTStandard);
+                m_pEsdlTransformer->processHPCCResult(context, mthdef, origResp.str(), respWriter.get(), logdata, ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
 
-        out.append(respWriter->str());
+                out.append(respWriter->str());
+            }
+            else if(implType==EsdlMethodImplProxy)
+                getSoapBody(out, origResp);
+            else
+                m_pEsdlTransformer->process(context, EsdlResponseMode, srvdef.queryName(), mthdef.queryName(), out, origResp.str(), ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
+        }
     }
-    else if(isproxy)
-        getSoapBody(out, soapresp);
-    else
-        m_pEsdlTransformer->process(context, EsdlResponseMode, srvdef.queryName(), mthdef.queryName(), out, soapresp.str(), ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
 
-    handleResultLogging(context, tgtcfg.get(), req,  soapresp.str(), out.str());
+    handleResultLogging(context, tgtcfg.get(), req,  origResp.str(), out.str());
     ESPLOG(LogMax,"Customer Response: %s", out.str());
 }
 
@@ -875,6 +986,7 @@ void EsdlBindingImpl::addService(const char * name,
                     name = loadedservicename.str();
                     m_espServiceName.set(name);
                     m_pESDLService->m_espServiceType.set(name);
+                    m_pESDLService->m_esdl.set(m_esdl);
                 }
 
                 if (srvdef)
@@ -924,6 +1036,10 @@ void EsdlBindingImpl::initEsdlServiceInfo(IEsdlDefService &srvdef)
     xsltpath.append("xslt/esxdl2xsd.xslt");
     m_xsdgen->loadTransform(xsltpath, xsdparams, EsdlXslToXsd );
     m_xsdgen->loadTransform(xsltpath, wsdlparams, EsdlXslToWsdl );
+
+
+//   xsltpath.set(getCFD()).append("xslt/esdl2java_srvbase.xslt");
+//   m_xsdgen->loadTransform(xsltpath, NULL, EsdlXslToJavaPlugin );
 }
 
 void EsdlBindingImpl::getSoapMessage(StringBuffer& soapmsg,
@@ -1341,6 +1457,110 @@ StringBuffer &EsdlBindingImpl::generateNamespace(IEspContext &context,
     return ns.toLowerCase();
 }
 
+
+int EsdlBindingImpl::onJavaPlugin(IEspContext &context,
+                               CHttpRequest* request,
+                               CHttpResponse* response,
+                               const char *serviceName,
+                               const char *methodName)
+{
+    StringBuffer serviceQName;
+    StringBuffer methodQName;
+    StringBuffer out;
+
+    Owned<CSoapFault> soapFault;
+
+    if (!serviceName || !*serviceName)
+        serviceName = m_espServiceName.get();
+
+    if (!m_esdl || !qualifyServiceName(context, serviceName, methodName, serviceQName, &methodQName))
+    {
+        response->setStatus(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+        out.set("The service has not been properly loaded.");
+    }
+    else
+    {
+        StringBuffer ns;
+        generateNamespace(context, request, serviceName, methodName, ns);
+
+        try
+        {
+            Owned<IEsdlDefObjectIterator> it = m_esdl->getDependencies(serviceName, methodName, context.getClientVersion(), context.queryRequestParameters(), 0);
+            m_xsdgen->toJavaService( *it, out, EsdlXslToJavaServiceBase, context.queryRequestParameters(), 0);
+        }
+        catch (IException *E)
+        {
+            throw makeWsException(*E, WSERR_CLIENT , "ESP");
+        }
+        catch (...)
+        {
+            throw makeWsException(ERR_ESDL_BINDING_INTERNERR, WSERR_CLIENT , "ESP", "Could not generate JavaPlugin for this service." );
+        }
+        response->setStatus(HTTP_STATUS_OK);
+    }
+
+    response->setContent(out.str());
+    response->setContentType(HTTP_TYPE_TEXT_PLAIN_UTF8);
+    response->send();
+
+    return 0;
+}
+
+int EsdlBindingImpl::onGet(CHttpRequest* request, CHttpResponse* response)
+{
+    Owned<IMultiException> me = MakeMultiException("DynamicESDL");
+
+    try
+    {
+        IEspContext *context = request->queryContext();
+        IProperties *parms = request->queryParameters();
+
+        const char *thepath = request->queryPath();
+
+        StringBuffer root;
+        firstPathNode(thepath, root);
+
+        if (!strieq(root, "esdl"))
+            return EspHttpBinding::onGet(request, response);
+
+        StringBuffer action;
+        nextPathNode(thepath, action);
+        if(!strieq(action, "plugin"))
+            return EspHttpBinding::onGet(request, response);
+        StringBuffer language;
+        nextPathNode(thepath, language);
+        if (!strieq(language, "java"))
+            throw MakeStringException(-1, "Unsupported embedded language %s", language.str());
+
+        StringBuffer servicename;
+        nextPathNode(thepath, servicename);
+        if (!servicename.length())
+            throw MakeStringExceptionDirect(-1, "Service name required to generate Java plugin code");
+
+        StringBuffer methodname;
+        nextPathNode(thepath, methodname);
+
+        return onJavaPlugin(*context, request, response, servicename, methodname);
+    }
+    catch (IMultiException* mex)
+    {
+        me->append(*mex);
+        mex->Release();
+    }
+    catch (IException* e)
+    {
+        me->append(*e);
+    }
+    catch (...)
+    {
+        me->append(*MakeStringExceptionDirect(-1, "Unknown Exception"));
+    }
+
+    response->handleExceptions(getXslProcessor(), me, "DynamicESDL", "", StringBuffer(getCFD()).append("./smc_xslt/exceptions.xslt").str());
+    return 0;
+}
+
+
 int EsdlBindingImpl::onGetXsd(IEspContext &context,
                               CHttpRequest* request,
                               CHttpResponse* response,

+ 19 - 0
esp/services/esdl_svc_engine/esdl_binding.hpp

@@ -25,6 +25,7 @@
 #include "jptree.hpp"
 #include "xsdparser.hpp"
 #include "loggingmanager.h"
+#include "eclrtl.hpp"
 
 static const char* ESDL_DEFS_ROOT_PATH="/ESDL/Definitions/";
 static const char* ESDL_DEF_PATH="/ESDL/Definitions/Definition";
@@ -62,12 +63,16 @@ static const char* ESDL_METHOD_HELP="help";
 #define REQ_REF_NUM_NAME    "_req_ref_num"
 #define MCACHE_OBJECT_KEY   "_mcache_object_key_"
 
+namespace javaembed { IEmbedContext* getEmbedContext(); }
+
 class EsdlServiceImpl : public CInterface, implements IEspService
 {
 private:
     IEspContainer *container;
     MapStringToMyClass<ISmartSocketFactory> connMap;
+    MapStringToMyClass<IEmbedServiceContext> javaServiceMap;
     Owned<ILoggingManager> loggingManager;
+    Owned<IEmbedContext> javaplugin;
 
 public:
     StringBuffer                m_espServiceType;
@@ -76,6 +81,7 @@ public:
     Owned<IPropertyTree>        m_pServiceConfig;
     Owned<IPropertyTree>        m_pServiceMethodTargets;
     Owned<IEsdlTransformer>     m_pEsdlTransformer;
+    Owned<IEsdlDefinition>      m_esdl;
 
 public:
     IMPLEMENT_IINTERFACE;
@@ -87,6 +93,12 @@ public:
     {
         return m_espServiceType.str();
     }
+    IEmbedContext &ensureJavaEmbeded()
+    {
+        if (!javaplugin)
+            javaplugin.setown(javaembed::getEmbedContext());
+        return *javaplugin;
+    }
 
     virtual bool init(const char * name, const char * type, IPropertyTree * cfg, const char * process)
     {
@@ -115,6 +127,9 @@ public:
     virtual bool loadLogggingManager();
     virtual void init(const IPropertyTree *cfg, const char *process, const char *service);
     virtual void configureTargets(IPropertyTree *cfg, const char *service);
+    void configureJavaMethod(const char *method, IPropertyTree &entry);
+    void configureUrlMethod(const char *method, IPropertyTree &entry);
+
     virtual void handleServiceRequest(IEspContext &context, IEsdlDefService &srvdef, IEsdlDefMethod &mthdef, Owned<IPropertyTree> &tgtcfg, Owned<IPropertyTree> &tgtctx, const char *ns, const char *schema_location, IPropertyTree *req, StringBuffer &out, StringBuffer &logdata, unsigned int flags);
     virtual void generateTransactionId(IEspContext & context, StringBuffer & trxid)=0;
     void generateTargetURL(IEspContext & context, IPropertyTree *srvinfo, StringBuffer & url, bool isproxy);
@@ -289,6 +304,8 @@ public:
     {
     }
 
+    virtual int onGet(CHttpRequest* request, CHttpResponse* response);
+
     virtual void initEsdlServiceInfo(IEsdlDefService &srvdef);
 
     virtual void addService(const char * name, const char * host, unsigned short port, IEspService & service);
@@ -302,6 +319,8 @@ public:
     int onGetXsd(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *serviceName, const char *methodName);
     virtual bool getSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, const char *service, const char *method, bool standalone);
     int onGetWsdl(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *serviceName, const char *methodName);
+    int onJavaPlugin(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *serviceName, const char *methodName);
+
     int onGetXForm(IEspContext &context, CHttpRequest* request,   CHttpResponse* response, const char *serv, const char *method);
     virtual int onGetFile(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *pathex);
     int getJsonTestForm(IEspContext &context, CHttpRequest* request, CHttpResponse* response);

+ 1 - 0
esp/services/ws_esdlconfig/CMakeLists.txt

@@ -42,6 +42,7 @@ include_directories (
          ${HPCC_SOURCE_DIR}/system/security/LdapSecurity
          ${HPCC_SOURCE_DIR}/system/mp
          ${HPCC_SOURCE_DIR}/system/xmllib
+         ${HPCC_SOURCE_DIR}/rtl/eclrtl
          ${HPCC_SOURCE_DIR}/esp/platform
          ${HPCC_SOURCE_DIR}/esp/clients
          ${HPCC_SOURCE_DIR}/esp/bindings

+ 2 - 0
esp/xslt/CMakeLists.txt

@@ -42,6 +42,8 @@ FOREACH( iFILES
     ${CMAKE_CURRENT_SOURCE_DIR}/passwordupdate.xsl
     ${CMAKE_CURRENT_SOURCE_DIR}/esdl2ecl.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esxdl2xsd.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvbase.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvdummy.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/roxie_page.xsl
 )
     Install ( FILES ${iFILES} DESTINATION componentfiles/xslt COMPONENT Runtime )

+ 212 - 0
esp/xslt/esdl2java_srvbase.xslt

@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+##############################################################################
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##############################################################################
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
+
+    <xsl:template match="esxdl">
+package <xsl:value-of select="EsdlService/@name"/>;
+import java.util.*;
+import java.math.*;
+
+class EsdlContext
+{
+    String username;
+    Integer clientMajorVersion;
+    Integer clientMinorVersion;
+}
+
+        <xsl:apply-templates select="EsdlEnumType"/>
+        <xsl:apply-templates select="EsdlStruct"/>
+        <xsl:apply-templates select="EsdlRequest"/>
+        <xsl:apply-templates select="EsdlResponse"/>
+        <xsl:apply-templates select="EsdlService"/>
+
+    </xsl:template>
+
+    <xsl:template match="EsdlStruct|EsdlRequest|EsdlResponse">
+class <xsl:value-of select="@name"/><xsl:if test="@base_type"> extends <xsl:value-of select="@base_type"/></xsl:if>
+{
+<xsl:apply-templates select="EsdlElement|EsdlArray|EsdlEnum"/>}
+    </xsl:template>
+
+    <xsl:template name="outputJavaPrimitive">
+        <xsl:param name="typename"/>
+        <xsl:choose>
+            <xsl:when test="$typename='bool'"><xsl:value-of select="'Boolean'"/></xsl:when>
+            <xsl:when test="$typename='boolean'"><xsl:value-of select="'Boolean'"/></xsl:when>
+            <xsl:when test="$typename='decimal'"><xsl:value-of select="'BigDecimal'"/></xsl:when>
+            <xsl:when test="$typename='float'"><xsl:value-of select="'Float'"/></xsl:when>
+            <xsl:when test="$typename='double'"><xsl:value-of select="'Double'"/></xsl:when>
+            <xsl:when test="$typename='integer'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='int64'"><xsl:value-of select="'BigInteger'"/></xsl:when>
+            <xsl:when test="$typename='long'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='int'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='short'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='nonPositiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='negativeInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='nonNegativeInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsigned'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedLong'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedInt'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedShort'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedByte'"><xsl:value-of select="'Byte'"/></xsl:when>
+            <xsl:when test="$typename='positiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='base64Binary'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='string'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='xsdString'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='normalizedString'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='binary'"><xsl:value-of select="'Byte'"/></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$typename"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+    <xsl:template match="EsdlArray">
+        <xsl:variable name="primitive">
+	        <xsl:call-template name="outputJavaPrimitive">
+	           <xsl:with-param name="typename">
+			<xsl:choose>
+			    <xsl:when test="@type"><xsl:value-of select="@type"/></xsl:when>
+			    <xsl:when test="@complex_type"><xsl:value-of select="@complex_type"/></xsl:when>
+			</xsl:choose>
+	           </xsl:with-param>
+	        </xsl:call-template>
+        </xsl:variable>
+            <xsl:text>    public </xsl:text>ArrayList&lt;<xsl:value-of select="$primitive"/>&gt;<xsl:text> </xsl:text><xsl:value-of select="@name"/>=new ArrayList&lt;<xsl:value-of select="$primitive"/>&gt;();<xsl:text>
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlElement">
+        <xsl:variable name="primitive">
+	        <xsl:call-template name="outputJavaPrimitive">
+	           <xsl:with-param name="typename">
+			<xsl:choose>
+			    <xsl:when test="@type"><xsl:value-of select="@type"/></xsl:when>
+			    <xsl:when test="@complex_type"><xsl:value-of select="@complex_type"/></xsl:when>
+			</xsl:choose>
+	           </xsl:with-param>
+	        </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="useQuotes">
+          <xsl:choose>
+            <xsl:when test="$primitive='String'"><xsl:value-of select="true()"/></xsl:when>
+            <xsl:otherwise><xsl:value-of select="false()"/></xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:text>    public </xsl:text>
+	<xsl:value-of select="$primitive"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:choose>
+            <xsl:when test="@type='binary'"><xsl:value-of select="'[]'"/></xsl:when>
+            <xsl:when test="@default">
+		<xsl:text> = new </xsl:text><xsl:value-of select="$primitive"/><xsl:text>(</xsl:text>
+		<xsl:choose>
+	            <xsl:when test="$useQuotes">"<xsl:value-of select="@default"/>"</xsl:when>
+	            <xsl:when test="$primitive='Boolean'">
+			<xsl:choose>
+			    <xsl:when test="@default='true'"><xsl:value-of select="'true'"/></xsl:when>
+			    <xsl:when test="@default='1'"><xsl:value-of select="'true'"/></xsl:when>
+			    <xsl:otherwise><xsl:value-of select="'false'"/></xsl:otherwise>
+	                </xsl:choose>
+                    </xsl:when>
+	            <xsl:otherwise><xsl:value-of select="@default"/></xsl:otherwise>
+                </xsl:choose>
+		<xsl:text>)</xsl:text>
+            </xsl:when>
+        </xsl:choose>
+        <xsl:text>;
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlEnum">
+        <xsl:variable name="enum_type" select="@enum_type"/>
+        <xsl:variable name="primitive">
+	        <xsl:call-template name="outputJavaPrimitive">
+	           <xsl:with-param name="typename">
+                     <xsl:value-of select="@enum_type"/>
+	           </xsl:with-param>
+	        </xsl:call-template>
+        </xsl:variable>
+        <xsl:text>    public </xsl:text>
+	<xsl:value-of select="$primitive"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="@name"/>
+            <xsl:if test="@default">
+                <xsl:text> = </xsl:text><xsl:value-of select="$primitive"/>.fromString<xsl:text>(</xsl:text>"<xsl:value-of select="@default"/>")
+            </xsl:if>
+        <xsl:text>;
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlService">
+public class <xsl:value-of select="@name"/>ServiceBase
+{
+        <xsl:for-each select="EsdlMethod">
+    public <xsl:value-of select="@response_type"/><xsl:text> </xsl:text><xsl:value-of select="@name"/>(EsdlContext context, <xsl:value-of select="@request_type"/> request){return null;}
+        </xsl:for-each>
+}
+    </xsl:template>
+
+    <xsl:template match="EsdlEnumType">
+      <xsl:if test="EsdlEnumItem">
+    enum <xsl:value-of select="@name"/><xsl:text> {
+</xsl:text>
+        <xsl:for-each select="EsdlEnumItem">
+          <xsl:text>        </xsl:text><xsl:value-of select="@name"/><xsl:text> </xsl:text>("<xsl:value-of select="@enum"/><xsl:text>")</xsl:text>
+           <xsl:choose>
+             <xsl:when test="position() != last()">
+              <xsl:text>,
+</xsl:text>
+             </xsl:when>
+             <xsl:otherwise>
+              <xsl:text>;
+</xsl:text>
+             </xsl:otherwise>
+           </xsl:choose>
+        </xsl:for-each>
+            private final String name;       
+
+            private<xsl:text> </xsl:text><xsl:value-of select="@name"/>(String s) {
+                name = s;
+            }
+
+            public boolean equalsName(String otherName) {
+                return (otherName == null) ? false : name.equals(otherName);
+            }
+
+            public String toString() {
+               return this.name;
+            }
+            public static<xsl:text> </xsl:text><xsl:value-of select="@name"/> fromString(String text)
+            {
+              if (text != null)
+              {
+                  for (<xsl:value-of select="@name"/> val :<xsl:text> </xsl:text><xsl:value-of select="@name"/>.values()) {
+                    if (text.equalsIgnoreCase(val.toString())) {
+                      return val;
+                    }
+                  }
+               }
+             return null;
+            }        
+        }
+      </xsl:if>
+    </xsl:template>
+</xsl:stylesheet>
+

+ 44 - 0
esp/xslt/esdl2java_srvdummy.xslt

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+##############################################################################
+#    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##############################################################################
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
+
+    <xsl:template match="esxdl">
+package <xsl:value-of select="EsdlService/@name"/>;
+import <xsl:value-of select="EsdlService/@name"/>.*;
+
+        <xsl:apply-templates select="EsdlService"/>
+
+    </xsl:template>
+
+    <xsl:template match="EsdlService">
+public class <xsl:value-of select="@name"/>ServiceDummy extends <xsl:value-of select="@name"/>ServiceBase
+{
+        <xsl:for-each select="EsdlMethod">
+    public <xsl:value-of select="@response_type"/><xsl:text> </xsl:text><xsl:value-of select="@name"/>(EsdlContext context, <xsl:value-of select="@request_type"/> request)
+    {
+        System.out.println("Method <xsl:value-of select="@name"/><xsl:text> </xsl:text>of Service <xsl:value-of select="../@name"/><xsl:text> </xsl:text>called!");
+	<xsl:value-of select="@response_type"/><xsl:text> </xsl:text> response = new <xsl:value-of select="@response_type"/>();
+        return response;
+    }
+        </xsl:for-each>
+}
+    </xsl:template>
+</xsl:stylesheet>

+ 170 - 0
esp/xslt/esdl2javaplugin.xslt

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+##############################################################################
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##############################################################################
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
+
+    <xsl:template match="esxdl">
+import java.util.*;
+        <!--xsl:apply-templates select="EsdlEnumType" /-->
+        <xsl:apply-templates select="EsdlStruct"/>
+        <xsl:apply-templates select="EsdlRequest"/>
+        <xsl:apply-templates select="EsdlResponse"/>
+        <xsl:apply-templates select="EsdlService"/>
+
+    </xsl:template>
+
+    <xsl:template match="EsdlStruct|EsdlRequest|EsdlResponse">
+public class <xsl:value-of select="@name"/><xsl:if test="@base_type"> extends <xsl:value-of select="@base_type"/></xsl:if>
+{
+<xsl:apply-templates select="EsdlElement|EsdlArray|EsdlEnum"/>
+}
+    </xsl:template>
+
+    <xsl:template name="ouputJavaPrimitive">
+        <xsl:param name="typename"/>
+        <xsl:choose>
+            <xsl:when test="$typename='bool'"><xsl:value-of select="'Boolean'"/></xsl:when>
+            <xsl:when test="$typename='boolean'"><xsl:value-of select="'Boolean'"/></xsl:when>
+            <xsl:when test="$typename='decimal'"><xsl:value-of select="'BigDecimal'"/></xsl:when>
+            <xsl:when test="$typename='float'"><xsl:value-of select="'Float'"/></xsl:when>
+            <xsl:when test="$typename='double'"><xsl:value-of select="'Double'"/></xsl:when>
+            <xsl:when test="$typename='integer'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='int64'"><xsl:value-of select="'BigInteger'"/></xsl:when>
+            <xsl:when test="$typename='long'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='int'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='short'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='nonPositiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='negativeInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='nonNegativeInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsigned'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedLong'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedInt'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedShort'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='unsignedByte'"><xsl:value-of select="'Byte'"/></xsl:when>
+            <xsl:when test="$typename='positiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='base64Binary'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='string'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='xsdString'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='normalizedString'"><xsl:value-of select="'String'"/></xsl:when>
+            <xsl:when test="$typename='binary'"><xsl:value-of select="'Byte'"/></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$typename"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template match="EsdlElement|EsdlArray|EsdlEnum">
+        <xsl:variable name="enum_type" select="@enum_type"/>
+        <xsl:text>    public </xsl:text>
+
+        <xsl:variable name="primitive">
+	        <xsl:call-template name="ouputJavaPrimitive">
+	           <xsl:with-param name="typename">
+			<xsl:choose>
+			    <xsl:when test="@enum_type"><xsl:value-of select="esxdl/EsdlEnumType[@name=$enum_type]/@base_type"/></xsl:when>
+			    <xsl:when test="@type"><xsl:value-of select="@type"/></xsl:when>
+			    <xsl:when test="@complex_type"><xsl:value-of select="@complex_type"/></xsl:when>
+			</xsl:choose>
+	           </xsl:with-param>
+	        </xsl:call-template>
+        </xsl:variable>
+	<xsl:value-of select="$primitive"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:choose>
+            <xsl:when test="@type='binary'"><xsl:value-of select="'[]'"/></xsl:when>
+            <xsl:when test="local-name()='EsdlArray'"><xsl:value-of select="'[]'"/></xsl:when>
+            <xsl:when test="@default">
+		<xsl:text> = new </xsl:text><xsl:value-of select="$primitive"/><xsl:text>(</xsl:text>
+		<xsl:choose>
+	            <xsl:when test="$primitive='String'">"<xsl:value-of select="@default"/>"</xsl:when>
+	            <xsl:when test="$primitive='Boolean'">
+			<xsl:choose>
+			    <xsl:when test="@default='true'"><xsl:value-of select="'true'"/></xsl:when>
+			    <xsl:when test="@default='1'"><xsl:value-of select="'true'"/></xsl:when>
+			    <xsl:otherwise><xsl:value-of select="'false'"/></xsl:otherwise>
+	                </xsl:choose>
+                    </xsl:when>
+	            <xsl:otherwise><xsl:value-of select="@default"/></xsl:otherwise>
+                </xsl:choose>
+		<xsl:text>)</xsl:text>
+            </xsl:when>
+        </xsl:choose>
+        <xsl:text>;
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlService">
+public class <xsl:value-of select="@name"/>
+{
+        <xsl:for-each select="EsdlMethod">
+    public void <xsl:value-of select="@name"/>(<xsl:value-of select="@request_type"/> request, <xsl:value-of select="@response_type"/> response);
+        </xsl:for-each>
+}
+    </xsl:template>
+    <!--xsl:template match="EsdlEnumItem">
+        <xsd:enumeration>
+            <xsl:attribute name="value"><xsl:value-of select="@enum"/></xsl:attribute>
+        </xsd:enumeration>
+    </xsl:template>
+
+    <xsl:template match="EsdlEnumType">
+        <xsd:simpleType>
+            <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+            <xsl:if test="(EsdlEnumItem[@desc]) and EsdlEnumItem/@desc!=''">
+                <xsl:if test="not($no_annot_Param) or boolean($all_annot_Param)">
+                    <xsd:annotation>
+                        <xsd:appinfo>
+                            <xsl:apply-templates select="EsdlEnumItem" mode="annotation" />
+                        </xsd:appinfo>
+                    </xsd:annotation>
+                </xsl:if>
+            </xsl:if>
+            <xsd:restriction>
+                <xsl:attribute name="base">xsd:<xsl:value-of select="@base_type"/></xsl:attribute>
+                <xsl:apply-templates select="EsdlEnumItem"/>
+            </xsd:restriction>
+        </xsd:simpleType>
+    </xsl:template>
+
+    <xsl:template match="EsdlEnum">
+        <xsd:element>
+            <xsl:choose>
+                <xsl:when test="@required"></xsl:when>
+                <xsl:otherwise>
+                    <xsl:attribute name="minOccurs">0</xsl:attribute>
+                </xsl:otherwise>
+            </xsl:choose>
+            <xsl:attribute name="name">
+                <xsl:choose>
+                    <xsl:when test="@xml_tag"><xsl:value-of select="@xml_tag" /></xsl:when>
+                    <xsl:otherwise><xsl:value-of select="@name" /></xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <xsl:attribute name="type">
+                <xsl:choose>
+                    <xsl:when test="@xsd_type"><xsl:value-of select="@xsd_type" /></xsl:when>
+                    <xsl:when test="@enum_type">tns:<xsl:value-of select="@enum_type" /></xsl:when>
+                </xsl:choose>
+            </xsl:attribute>
+            <xsl:if test="@default or (@default='')">
+                <xsl:attribute name="default"><xsl:value-of select="@default"/></xsl:attribute>
+            </xsl:if>
+        </xsd:element>
+    </xsl:template-->
+</xsl:stylesheet>

+ 16 - 0
initfiles/examples/EsdlExample/EsdlExampleService.java

@@ -0,0 +1,16 @@
+package EsdlExample;
+
+public class EsdlExampleService extends EsdlExampleServiceBase
+{
+    int counter=0;
+    public JavaEchoPersonInfoResponse JavaEchoPersonInfo(EsdlContext context, JavaEchoPersonInfoRequest request)
+    {
+        System.out.println("Method EchoPersonInfo of Service EsdlExample called!");
+        JavaEchoPersonInfoResponse  response = new JavaEchoPersonInfoResponse();
+        response.count = new Integer(++counter);
+        response.Name = request.Name;
+        response.Addresses = request.Addresses;
+        return response;
+    }
+}
+

+ 37 - 0
initfiles/examples/EsdlExample/ReadMeFirst.txt

@@ -0,0 +1,37 @@
+You must have configured an instance of dynamicEsdl in this environment.  Either through configmgr or by editing environment.xml.  This document assumes dynamicESDL is running on "myesp" port 8088.
+
+Run the following from the node running the eclwatch server:
+
+Make a copy of the /opt/HPCCSystems/examples/EsdlExample folder.
+
+From EsdlExample copy folder:
+
+1. Generate java base classes (and dummy implementation file): 
+esdl java esdl_example.esdl EsdlExample --version=9
+
+2. Compile java base classes and example service (must have sudo access to place the classes in the default HPCC class location):
+sudo javac -g EsdlExampleServiceBase.java -cp /opt/HPCCSystems/classes -d /opt/HPCCSystems/classes/
+sudo javac -g EsdlExampleService.java -cp /opt/HPCCSystems/classes -d /opt/HPCCSystems/classes/
+
+3. Generate ecl layouts:
+esdl ecl esdl_example.esdl .
+
+4. Publish example roxie query:
+ecl publish roxie RoxieEchoPersonInfo.ecl
+
+5. Publish the esdl defined service to dynamicESDL:
+ esdl publish EsdlExample esdl_example.esdl --version 9 --overwrite
+
+5. Bind both java and roxie implementations to DynamicESDL
+esdl bind-service myesp 8088 esdlexample.1 EsdlExample --config esdl_binding.xml --overwrite
+
+6. Test calling the java service:
+soapplus -url http://.:8088/EsdlExample -i javarequest.xml
+
+7. Test calling the roxie service:
+soapplus -url http://.:8088/EsdlExample -i roxierequest.xml
+
+8. Interact with both services by browsing to:
+
+http://<DynamicEsdlIP>:8088
+

+ 3 - 0
initfiles/examples/EsdlExample/RoxieEchoPersonInfo.ecl

@@ -0,0 +1,3 @@
+import $.esdl_example;
+request := dataset([], esdl_example.t_RoxieEchoPersonInfoRequest) : stored('RoxieEchoPersonInfoRequest', few);
+output(request, named('RoxieEchoPersonInfoResponse'));

+ 5 - 0
initfiles/examples/EsdlExample/esdl_binding.xml

@@ -0,0 +1,5 @@
+ <Methods>
+    <Method name="JavaEchoPersonInfo" querytype="java" javamethod="EsdlExample.EsdlExampleService.JavaEchoPersonInfo"/>
+    <Method name="RoxieEchoPersonInfo" querytype="roxie" url="http://localhost:9876/roxie" queryname="RoxieEchoPersonInfo"/>
+</Methods>
+

+ 74 - 0
initfiles/examples/EsdlExample/esdl_example.esdl

@@ -0,0 +1,74 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+////////////////////////////////////////////////////////////
+
+ESPenum AddressType : string
+{
+    HOME("Home"),
+    WORK("Work"),
+    HOTEL("Hotel")
+};
+
+ESPStruct NameInfo
+{
+    string First("Joe");
+    string Last("Doe");
+};
+
+ESPStruct AddressInfo
+{
+    ESPenum AddressType type("Home");
+    string Line1;
+    string Line2;
+    string City;
+    string State;
+    int Zip(33487);  
+};
+
+ESPrequest JavaEchoPersonInfoRequest
+{
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
+ESPresponse JavaEchoPersonInfoResponse
+{
+     int count(0);
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
+ESPrequest RoxieEchoPersonInfoRequest
+{
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
+ESPresponse RoxieEchoPersonInfoResponse
+{
+     int count(0);
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
+ESPservice [version("0.01")] EsdlExample
+{
+    ESPmethod JavaEchoPersonInfo(JavaEchoPersonInfoRequest, JavaEchoPersonInfoResponse);
+    ESPmethod RoxieEchoPersonInfo(RoxieEchoPersonInfoRequest, RoxieEchoPersonInfoResponse);
+};
+

+ 27 - 0
initfiles/examples/EsdlExample/javarequest.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="urn:hpccsystems:ws:esdlexample:javaechopersoninfo@ver=0">
+ <soap:Body>
+  <JavaEchoPersonInfoRequest>
+   <Name>
+    <First>Joe</First>
+    <Last>Doe</Last>
+   </Name>
+   <Addresses>
+    <Address>
+     <Line1>105 Main St</Line1>
+     <City>Boca Raton</City>
+     <State>Florida</State>
+     <Zip>33487</Zip>
+     <type>Home</type>
+    </Address>
+    <Address>
+     <Line1>901 Main St</Line1>
+     <City>Orlando</City>
+     <State>Florida</State>
+     <Zip>77777</Zip>
+     <type>Work</type>
+    </Address>
+   </Addresses>
+  </JavaEchoPersonInfoRequest>
+ </soap:Body>
+</soap:Envelope>

+ 27 - 0
initfiles/examples/EsdlExample/roxierequest.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="urn:hpccsystems:ws:esdlexample:roxieechopersoninfo@ver=0">
+ <soap:Body>
+  <RoxieEchoPersonInfoRequest>
+   <Name>
+    <First>Joe</First>
+    <Last>Doe</Last>
+   </Name>
+   <Addresses>
+    <Address>
+     <Line1>105 Main St</Line1>
+     <City>Boca Raton</City>
+     <State>Florida</State>
+     <Zip>33487</Zip>
+     <type>Home</type>
+    </Address>
+    <Address>
+     <Line1>901 Main St</Line1>
+     <City>Orlando</City>
+     <State>Florida</State>
+     <Zip>77777</Zip>
+     <type>Work</type>
+    </Address>
+   </Addresses>
+  </RoxieEchoPersonInfoRequest>
+ </soap:Body>
+</soap:Envelope>

+ 15 - 0
plugins/Rembed/Rembed.cpp

@@ -602,6 +602,17 @@ public:
     ~REmbedFunctionContext()
     {
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual bool getBooleanResult()
     {
@@ -1088,6 +1099,10 @@ public:
     {
         return new REmbedFunctionContext(*queryGlobalState()->R, options);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 };
 
 extern IEmbedContext* getEmbedContext()

+ 15 - 0
plugins/cassandra/cassandraembed.cpp

@@ -1705,6 +1705,17 @@ public:
                                                  collection),
                   name);
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual void importFunction(size32_t lenChars, const char *text)
     {
@@ -1882,6 +1893,10 @@ public:
         else
             return new CassandraEmbedFunctionContext(ctx ? ctx->queryContextLogger() : queryDummyContextLogger(), flags, options);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 };
 
 extern IEmbedContext* getEmbedContext()

+ 2 - 0
plugins/javaembed/CMakeLists.txt

@@ -41,6 +41,8 @@ if (USE_JNI)
              ./../../common/deftype
              ./../../system/jlib
              ./../../roxie/roxiemem
+             ${HPCC_SOURCE_DIR}/esp/esdllib
+             ${HPCC_SOURCE_DIR}/common/thorhelper
              ${CMAKE_BINARY_DIR}
              ${CMAKE_BINARY_DIR}/oss
         )

+ 807 - 10
plugins/javaembed/javaembed.cpp

@@ -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();
     }
 };
 

+ 15 - 0
plugins/mysql/mysqlembed.cpp

@@ -1185,6 +1185,17 @@ public:
     {
         UNSUPPORTED("SET parameters");  // MySQL does support sets, so MIGHT be possible...
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual void importFunction(size32_t lenChars, const char *text)
     {
@@ -1256,6 +1267,10 @@ public:
         else
             return new MySQLEmbedFunctionContext(options);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 };
 
 extern IEmbedContext* getEmbedContext()

+ 26 - 0
plugins/pyembed/pyembed.cpp

@@ -1492,6 +1492,17 @@ public:
     ~Python27EmbedScriptContext()
     {
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual void importFunction(size32_t lenChars, const char *text)
     {
@@ -1534,6 +1545,17 @@ public:
     ~Python27EmbedImportContext()
     {
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual void importFunction(size32_t lenChars, const char *utf)
     {
@@ -1576,6 +1598,10 @@ public:
         else
             return new Python27EmbedScriptContext(threadContext, options);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 };
 
 extern IEmbedContext* getEmbedContext()

+ 14 - 0
plugins/sqlite3/sqlite3.cpp

@@ -530,6 +530,16 @@ public:
     {
         UNSUPPORTED("SET parameters");
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
 
     virtual void importFunction(size32_t lenChars, const char *text)
     {
@@ -591,6 +601,10 @@ public:
         else
             return new SqLite3EmbedFunctionContext(flags, options);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 };
 
 extern IEmbedContext* getEmbedContext()

+ 15 - 0
plugins/v8embed/v8embed.cpp

@@ -460,6 +460,17 @@ public:
         isolate->Exit();
         isolate->Dispose();
     }
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+    {
+        return NULL;
+    }
+    virtual void paramWriterCommit(IInterface *writer)
+    {
+    }
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+    {
+    }
+
 
     virtual void bindBooleanParam(const char *name, bool val)
     {
@@ -946,6 +957,10 @@ public:
         }
         return LINK(theFunctionContext);
     }
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options)
+    {
+        throwUnexpected();
+    }
 } theEmbedContext;
 
 

+ 9 - 0
rtl/eclrtl/eclrtl.hpp

@@ -815,6 +815,14 @@ interface IEmbedFunctionContext : extends IInterface
     virtual void bindFloatParam(const char *name, float val) = 0;
     virtual void bindSignedSizeParam(const char *name, int size, __int64 val) = 0;
     virtual void bindUnsignedSizeParam(const char *name, int size, unsigned __int64 val) = 0;
+    virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)=0;
+    virtual void paramWriterCommit(IInterface *writer)=0;
+    virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)=0;
+};
+
+interface IEmbedServiceContext : extends IInterface
+{
+    virtual IEmbedFunctionContext *createFunctionContext(const char *function) = 0;
 };
 
 enum EmbedFlags { EFembed = 1, EFimport = 2, EFnoreturn = 4, EFnoparams = 8 }; // For createFunctionContext flags
@@ -824,6 +832,7 @@ interface IEmbedContext : extends IInterface
 {
     virtual IEmbedFunctionContext *createFunctionContext(unsigned flags, const char *options) = 0; // legacy
     virtual IEmbedFunctionContext *createFunctionContextEx(ICodeContext * ctx, unsigned flags, const char *options) = 0;
+    virtual IEmbedServiceContext *createServiceContext(const char *service, unsigned flags, const char *options) = 0;
     // MORE - add syntax checked here!
 };
 

+ 1 - 1
tools/esdlcmd/esdl-publish.cpp

@@ -45,7 +45,7 @@ protected:
     Owned<EsdlCmdHelper> esdlHelper;
 
 public:
-    EsdlPublishCmdCommon()
+    EsdlPublishCmdCommon() : optWSProcAddress("."), optWSProcPort("8010")
     {
         esdlHelper.setown(EsdlCmdHelper::createEsdlHelper());
     }

+ 12 - 10
tools/esdlcmd/esdlcmd_common.hpp

@@ -131,18 +131,18 @@ public:
 
 class EsdlCmdHelper : public CInterface
 {
-protected:
+public:
     Owned<IEsdlDefinition> esdlDef;
-    Owned<IEsdlDefinitionHelper> helper;
+    Owned<IEsdlDefinitionHelper> defHelper;
     Owned<IFile> serviceDefFile;
 
+public:
     EsdlCmdHelper()
     {
         esdlDef.set(createEsdlDefinition());
-        helper.set(createEsdlDefinitionHelper());
+        defHelper.set(createEsdlDefinitionHelper());
     }
 
-public:
     IMPLEMENT_IINTERFACE;
 
     static EsdlCmdHelper * createEsdlHelper()
@@ -150,7 +150,7 @@ public:
         return new EsdlCmdHelper();
     }
 
-    void getServiceESXDL(const char * sourceFileName, const char * serviceName, StringBuffer & xmlOut, double version, IProperties *opts=NULL, unsigned flags=0)
+    void loadDefinition(const char * sourceFileName, const char * serviceName, double version)
     {
         if (!esdlDef.get())
             esdlDef.set(createEsdlDefinition());
@@ -171,6 +171,11 @@ public:
                 loadEsdlDef(sourceFileName);
             }
         }
+    }
+
+    void getServiceESXDL(const char * sourceFileName, const char * serviceName, StringBuffer & xmlOut, double version, IProperties *opts=NULL, unsigned flags=0)
+    {
+        loadDefinition(sourceFileName, serviceName, version);
 
         if (esdlDef)
         {
@@ -179,7 +184,7 @@ public:
             if( deps )
             {
                 xmlOut.appendf( "<esxdl name=\"%s\">", serviceName);
-                helper->toXML( *deps, xmlOut, version, opts, flags );
+                defHelper->toXML( *deps, xmlOut, version, opts, flags );
                 xmlOut.append("</esxdl>");
             }
             else
@@ -288,13 +293,10 @@ public:
 class EsdlHelperConvertCmd : public EsdlConvertCmd
 {
 protected:
-    Owned<IEsdlDefinition> esdlDef;
-    Owned<IEsdlDefinitionHelper> helper;
+    EsdlCmdHelper cmdHelper;
 public:
     EsdlHelperConvertCmd()
     {
-        esdlDef.set(createEsdlDefinition());
-        helper.set(createEsdlDefinitionHelper());
     }
 
     virtual void usage()

+ 247 - 11
tools/esdlcmd/esdlcmd_core.cpp

@@ -196,18 +196,18 @@ public:
     virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
     {
         TimeSection ts("transforming via XSLT");
-        helper->toXSD( objs, target, EsdlXslToXsd, optVersion, opts, NULL, optFlags );
+        cmdHelper.defHelper->toXSD( objs, target, EsdlXslToXsd, optVersion, opts, NULL, optFlags );
     }
 
     virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
     {
         TimeSection ts("loading XSLT");
-        helper->loadTransform( xsltpath, params, EsdlXslToXsd );
+        cmdHelper.defHelper->loadTransform( xsltpath, params, EsdlXslToXsd );
     }
 
     virtual void setTransformParams(IProperties *params )
     {
-        helper->setTransformParams(EsdlXslToXsd, params);
+        cmdHelper.defHelper->setTransformParams(EsdlXslToXsd, params);
     }
 
     virtual int processCMD()
@@ -215,7 +215,7 @@ public:
         loadServiceDef();
         createOptionals();
 
-        Owned<IEsdlDefObjectIterator> structs = esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
 
         if( optRawOutput )
         {
@@ -292,7 +292,7 @@ public:
             StringBuffer empty;
 
             xmlOut.appendf( "<esxdl name=\"%s\">", optService.get());
-            helper->toXML( obj, xmlOut, optVersion, opts.get(), optFlags );
+            cmdHelper.defHelper->toXML( obj, xmlOut, optVersion, opts.get(), optFlags );
             xmlOut.append("</esxdl>");
 
             saveAsFile( optPreprocessOutputDir.get(), empty, xmlOut.str(), NULL );
@@ -354,7 +354,7 @@ public:
                     // Web Service at a time, and must load files by explicitly loading
                     // only the top-level ws_<service> definition file, and allowing the
                     // load code to handle loading only the minimal set of required includes
-                    esdlDef->addDefinitionsFromFile( serviceDef->queryFilename() );
+                    cmdHelper.esdlDef->addDefinitionsFromFile( serviceDef->queryFilename() );
                 }
                 else
                 {
@@ -394,7 +394,7 @@ public:
        /*
        StringBuffer ns_optionals;
        //IProperties *params = context.queryRequestParameters();
-       Owned<IPropertyIterator> esdl_optionals = esdlDef->queryOptionals()->getIterator();
+       Owned<IPropertyIterator> esdl_optionals = cmdHelper.esdlDef->queryOptionals()->getIterator();
        ForEach(*esdl_optionals)
        {
            const char *key = esdl_optionals->getPropKey();
@@ -518,18 +518,18 @@ public:
     virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
     {
         TimeSection ts("transforming via XSLT");
-        helper->toWSDL(objs, target, EsdlXslToWsdl, optVersion, opts, NULL, optFlags);
+        cmdHelper.defHelper->toWSDL(objs, target, EsdlXslToWsdl, optVersion, opts, NULL, optFlags);
     }
 
     virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
     {
         TimeSection ts("loading XSLT");
-        helper->loadTransform( xsltpath, params, EsdlXslToWsdl );
+        cmdHelper.defHelper->loadTransform( xsltpath, params, EsdlXslToWsdl );
     }
 
     virtual void setTransformParams(IProperties *params )
     {
-        helper->setTransformParams(EsdlXslToWsdl, params);
+        cmdHelper.defHelper->setTransformParams(EsdlXslToWsdl, params);
     }
 
     virtual int processCMD()
@@ -537,7 +537,7 @@ public:
         loadServiceDef();
         createOptionals();
 
-        Owned<IEsdlDefObjectIterator> structs = esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
 
         if( optRawOutput )
         {
@@ -605,6 +605,240 @@ public:
     StringAttr optWsdlAddress;
 };
 
+#define XSLT_ESDL2JAVABASE "esdl2java_srvbase.xslt"
+#define XSLT_ESDL2JAVADUMMY "esdl2java_srvdummy.xslt"
+
+class Esdl2JavaCmd : public EsdlHelperConvertCmd
+{
+public:
+    Esdl2JavaCmd() : optVersion(0), optFlags(0)
+    {}
+
+    virtual bool parseCommandLineOptions(ArgvIterator &iter)
+    {
+        if (iter.done())
+        {
+            usage();
+            return false;
+        }
+
+        //First two parameters' order is fixed.
+        for (int par = 0; par < 2 && !iter.done(); par++)
+        {
+            const char *arg = iter.query();
+            if (*arg != '-')
+            {
+                if (optSource.isEmpty())
+                    optSource.set(arg);
+                else if (optService.isEmpty())
+                    optService.set(arg);
+                else
+                {
+                    fprintf(stderr, "\nunrecognized argument detected before required parameters: %s\n", arg);
+                    usage();
+                    return false;
+                }
+            }
+            else
+            {
+                fprintf(stderr, "\noption detected before required parameters: %s\n", arg);
+                usage();
+                return false;
+            }
+
+            iter.next();
+        }
+
+        for (; !iter.done(); iter.next())
+        {
+            if (parseCommandLineOption(iter))
+                continue;
+
+            if (matchCommandLineOption(iter, true)!=EsdlCmdOptionMatch)
+                return false;
+        }
+
+        return true;
+    }
+
+    virtual bool parseCommandLineOption(ArgvIterator &iter)
+    {
+        if (iter.matchOption(optVersionStr, ESDLOPT_VERSION))
+            return true;
+        if (iter.matchOption(optService, ESDLOPT_SERVICE))
+            return true;
+        if (iter.matchOption(optMethod, ESDLOPT_METHOD))
+            return true;
+        if (iter.matchOption(optXsltPath, ESDLOPT_XSLT_PATH))
+            return true;
+        if (iter.matchOption(optPreprocessOutputDir, ESDLOPT_PREPROCESS_OUT))
+            return true;
+        if (EsdlConvertCmd::parseCommandLineOption(iter))
+            return true;
+
+        return false;
+    }
+
+    esdlCmdOptionMatchIndicator matchCommandLineOption(ArgvIterator &iter, bool finalAttempt)
+    {
+        return EsdlConvertCmd::matchCommandLineOption(iter, true);
+    }
+
+    virtual bool finalizeOptions(IProperties *globals)
+    {
+        if (optSource.isEmpty())
+        {
+            usage();
+            throw( MakeStringException(0, "\nError: Source file parameter required\n"));
+        }
+
+        if( optService.isEmpty() )
+        {
+            usage();
+            throw( MakeStringException(0, "A service name must be provided") );
+        }
+
+        if (!optVersionStr.isEmpty())
+        {
+            optVersion = atof( optVersionStr.get() );
+            if( optVersion <= 0 )
+                throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
+        }
+
+        if (!optXsltPath.length())
+        {
+            StringBuffer binXsltPath;
+            getComponentFilesRelPathFromBin(binXsltPath);
+            binXsltPath.append("/xslt/");
+            StringBuffer temp;
+            if (checkFileExists(temp.append(binXsltPath).append(XSLT_ESDL2JAVABASE)))
+                optXsltPath.set(binXsltPath);
+            else
+                optXsltPath.set(temp.set(COMPONENTFILES_DIR).append("/xslt/"));
+        }
+        return true;
+    }
+
+    virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &out, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
+    {
+    }
+    virtual void loadTransform( StringBuffer &xsltpath, IProperties *params )
+    {
+    }
+
+    virtual void setTransformParams(IProperties *params )
+    {
+    }
+
+    virtual int processCMD()
+    {
+        cmdHelper.loadDefinition(optSource, optService, optVersion);
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, optVersion, NULL, optFlags );
+
+        if(!optPreprocessOutputDir.isEmpty())
+        {
+            outputRaw(*structs);
+        }
+
+        StringBuffer xsltpathServiceBase(optXsltPath);
+        xsltpathServiceBase.append(XSLT_ESDL2JAVABASE);
+        cmdHelper.defHelper->loadTransform( xsltpathServiceBase, NULL, EsdlXslToJavaServiceBase);
+        cmdHelper.defHelper->toJavaService( *structs, outputBuffer, EsdlXslToJavaServiceBase, NULL, optFlags );
+
+        VStringBuffer javaFileNameBase("%sServiceBase.java", optService.get());
+        saveAsFile(".", javaFileNameBase, outputBuffer.str(), NULL);
+
+        StringBuffer xsltpathServiceDummy(optXsltPath);
+        xsltpathServiceDummy.append(XSLT_ESDL2JAVADUMMY);
+        cmdHelper.defHelper->loadTransform( xsltpathServiceDummy, NULL, EsdlXslToJavaServiceDummy);
+        cmdHelper.defHelper->toJavaService( *structs, outputBuffer.clear(), EsdlXslToJavaServiceDummy, NULL, optFlags );
+
+        VStringBuffer javaFileNameDummy("%sServiceDummy.java", optService.get());
+        saveAsFile(".", javaFileNameDummy, outputBuffer.str(), NULL);
+
+        return 0;
+    }
+
+    void printOptions()
+    {
+        puts("Options:");
+        puts("  --version <version number> : Constrain to interface version\n");
+        puts("  --method <method name>[;<method name>]* : Constrain to list of specific method(s)\n" );
+        puts("  --xslt <xslt file path> : Path to xslt files used to transform EsdlDef to Java code\n" );
+        puts("  --preprocess-output <raw output directory> : Output pre-processed xml file to specified directory before applying XSLT transform\n" );
+        puts("  --show-inheritance : Turns off the collapse feature. Collapsing optimizes the XML output to strip out structures\n" );
+        puts("                        only used for inheritance, and collapses their elements into their child. That simplifies the\n" );
+        puts("                        stylesheet. By default this option is on.");
+    }
+
+    virtual void usage()
+    {
+        puts("Usage:");
+        puts("esdl java sourcePath serviceName [options]\n" );
+        puts("\nsourcePath must be absolute path to the ESDL Definition file containing the" );
+        puts("EsdlService definition for the service you want to work with.\n" );
+        puts("serviceName EsdlService definition for the service you want to work with.\n" );
+
+        printOptions();
+        EsdlConvertCmd::usage();
+    }
+
+    virtual void outputRaw( IEsdlDefObjectIterator& obj)
+    {
+        if (optPreprocessOutputDir.isEmpty())
+            return;
+
+        StringBuffer xml;
+
+        xml.appendf( "<esxdl name='%s'>", optService.get());
+        cmdHelper.defHelper->toXML( obj, xml, optVersion, NULL, optFlags );
+        xml.append("</esxdl>");
+        saveAsFile(optPreprocessOutputDir, NULL, xml, NULL );
+    }
+
+    void saveAsFile(const char * dir, const char *name, const char *text, const char *ext="")
+    {
+        StringBuffer path(dir);
+        if (name && *name)
+        {
+            if (*name!=PATHSEPCHAR)
+                addPathSepChar(path);
+            path.append(name);
+        }
+
+        if( ext && *ext )
+            path.append(ext);
+
+        Owned<IFile> file = createIFile(path);
+        Owned<IFileIO> io;
+        io.setown(file->open(IFOcreaterw));
+
+        DBGLOG("Writing java to file %s", file->queryFilename());
+
+        if (io.get())
+            io->write(0, strlen(text), text);
+        else
+            DBGLOG("File %s can't be created", file->queryFilename());
+    }
+
+    void setFlag( unsigned f ) { optFlags |= f; }
+    void unsetFlag( unsigned f ) { optFlags &= ~f; }
+
+
+public:
+    StringAttr optService;
+    StringAttr optXsltPath;
+    StringAttr optMethod;
+    StringAttr optPreprocessOutputDir;
+    StringAttr optVersionStr;
+    double optVersion;
+    unsigned optFlags;
+
+protected:
+    StringBuffer outputBuffer;
+    Owned<IProperties> params;
+};
+
 //=========================================================================================
 
 IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
@@ -615,6 +849,8 @@ IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
         return new Esdl2XSDCmd();
     if (strieq(cmdname, "ECL"))
         return new Esdl2EclCmd();
+    if (strieq(cmdname, "JAVA"))
+       return new Esdl2JavaCmd();
     if (strieq(cmdname, "WSDL"))
         return new Esdl2WSDLCmd();
     if (strieq(cmdname, "PUBLISH"))