Преглед изворни кода

HPCC-17484 Dynamic ESDL C++ Plugins

- Add XSLTs to generate base service hpp and cpp files and CMakeLists.txt
  etc.
- Add option "cpp" to esdl command line to generate all files needed,using
  the XSLTs
- Add support for processing c++ plugin method type in esdl_binding

Signed-off-by: mayx <yanrui.ma@lexisnexisrisk.com>
mayx пре 6 година
родитељ
комит
8a427e70b2

+ 2 - 2
esp/esdllib/esdl_def_helper.cpp

@@ -72,7 +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, 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 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 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);
+    virtual void toMicroService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId classType, IProperties *opts, unsigned flags);
 
 
     void loadTransformParams( EsdlXslTypeId xslId );
     void loadTransformParams( EsdlXslTypeId xslId );
 
 
@@ -303,7 +303,7 @@ void EsdlDefinitionHelper::loadTransformParams( EsdlXslTypeId xslId)
     }
     }
 }
 }
 
 
-void EsdlDefinitionHelper::toJavaService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId implType, IProperties *opts, unsigned flags)
+void EsdlDefinitionHelper::toMicroService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId implType, IProperties *opts, unsigned flags)
 {
 {
     StringBuffer xml;
     StringBuffer xml;
     int xmlLen = 0;
     int xmlLen = 0;

+ 8 - 2
esp/esdllib/esdl_def_helper.hpp

@@ -32,7 +32,13 @@ typedef enum EsdlXslTypeId_
     EsdlXslToXsd,
     EsdlXslToXsd,
     EsdlXslToWsdl,
     EsdlXslToWsdl,
     EsdlXslToJavaServiceBase,
     EsdlXslToJavaServiceBase,
-    EsdlXslToJavaServiceDummy
+    EsdlXslToJavaServiceDummy,
+    EsdlXslToCppServiceBaseHpp,
+    EsdlXslToCppServiceBaseCpp,
+    EsdlXslToCppServiceHpp,
+    EsdlXslToCppServiceCpp,
+    EsdlXslToCppCMake,
+    EsdlXslToCppTypes
 } EsdlXslTypeId;
 } EsdlXslTypeId;
 
 
 interface IEsdlDefinitionHelper : extends IInterface
 interface IEsdlDefinitionHelper : extends IInterface
@@ -44,7 +50,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, 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 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 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;
+    virtual void toMicroService( IEsdlDefObjectIterator& objs, StringBuffer &content, EsdlXslTypeId implType, IProperties *opts=NULL, unsigned flags=0 )=0;
 };
 };
 
 
 esdl_decl void removeEclHidden(IPropertyTree *depTree);
 esdl_decl void removeEclHidden(IPropertyTree *depTree);

+ 99 - 2
esp/services/esdl_svc_engine/esdl_binding.cpp

@@ -259,6 +259,46 @@ void EsdlServiceImpl::configureJavaMethod(const char *method, IPropertyTree &ent
     }
     }
 }
 }
 
 
+void EsdlServiceImpl::configureCppMethod(const char *method, IPropertyTree &entry, IEspPlugin*& plugin)
+{
+    const char *pluginName = entry.queryProp("@plugin");
+    if (!pluginName || !*pluginName)
+    {
+        DBGLOG("C++ plugin name is missing for method %s", method);
+        return;
+    }
+    const char *cppMethod = entry.queryProp("@method");
+    if (!cppMethod || !*cppMethod)
+    {
+        DBGLOG("C++ method name is missing for method %s", method);
+        return;
+    }
+
+    Owned<IEspPlugin> pluginHolder;
+    if (!plugin)
+    {
+        DBGLOG("Loading plugin %s", pluginName);
+        pluginHolder.setown(loadPlugin(pluginName));
+        plugin = pluginHolder.get();
+        if (!plugin || !plugin->isLoaded())
+        {
+            DBGLOG("C++ plugin %s could not be loaded for esdl method %s", pluginName, method);
+            return;
+        }
+        cppPluginMap.remove(pluginName);
+        cppPluginMap.setValue(pluginName, plugin);
+    }
+
+    cpp_service_method_t xproc = (cpp_service_method_t) plugin->getProcAddress(cppMethod);
+    if (!xproc)
+    {
+        DBGLOG("C++ method %s could not be loaded from plugin %s in esdl method %s", cppMethod, pluginName, method);
+        return;
+    }
+    cppProcMap.remove(method);
+    cppProcMap.setValue(method, xproc);
+}
+
 void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entry)
 void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entry)
 {
 {
     const char *url = entry.queryProp("@url");
     const char *url = entry.queryProp("@url");
@@ -414,6 +454,8 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
         else
         else
             classPath.append(INSTALL_DIR).append(PATHSEPCHAR).append("classes");
             classPath.append(INSTALL_DIR).append(PATHSEPCHAR).append("classes");
 
 
+        MapStringToMyClass<IEspPlugin> localCppPluginMap;
+
         Owned<IPropertyTreeIterator> iter = m_pServiceMethodTargets->getElements("Target");
         Owned<IPropertyTreeIterator> iter = m_pServiceMethodTargets->getElements("Target");
         ForEach(*iter)
         ForEach(*iter)
         {
         {
@@ -449,6 +491,20 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
             const char *type = methodCfg.queryProp("@querytype");
             const char *type = methodCfg.queryProp("@querytype");
             if (type && strieq(type, "java"))
             if (type && strieq(type, "java"))
                 configureJavaMethod(method, methodCfg, classPath);
                 configureJavaMethod(method, methodCfg, classPath);
+            else if (type && strieq(type, "cpp"))
+            {
+                const char* pluginName = methodCfg.queryProp("@plugin");
+                if (!pluginName || !*pluginName)
+                    DBGLOG("C++ plugin name is missing for method %s", method);
+                else
+                {
+                    IEspPlugin* plugin = localCppPluginMap.getValue(pluginName);
+                    bool loaded = (plugin != nullptr);
+                    configureCppMethod(method, methodCfg, plugin);
+                    if (!loaded && plugin != nullptr)
+                        localCppPluginMap.setValue(pluginName, plugin);
+                }
+            }
             else
             else
                 configureUrlMethod(method, methodCfg);
                 configureUrlMethod(method, methodCfg);
             DBGLOG("Method %s configured", method);
             DBGLOG("Method %s configured", method);
@@ -468,7 +524,8 @@ enum EsdlMethodImplType
     EsdlMethodImplRoxie,
     EsdlMethodImplRoxie,
     EsdlMethodImplWsEcl,
     EsdlMethodImplWsEcl,
     EsdlMethodImplProxy,
     EsdlMethodImplProxy,
-    EsdlMethodImplJava
+    EsdlMethodImplJava,
+    EsdlMethodImplCpp
 };
 };
 
 
 inline EsdlMethodImplType getEsdlMethodImplType(const char *querytype)
 inline EsdlMethodImplType getEsdlMethodImplType(const char *querytype)
@@ -483,6 +540,8 @@ inline EsdlMethodImplType getEsdlMethodImplType(const char *querytype)
             return EsdlMethodImplProxy;
             return EsdlMethodImplProxy;
         if (strieq(querytype, "java"))
         if (strieq(querytype, "java"))
             return EsdlMethodImplJava;
             return EsdlMethodImplJava;
+        if (strieq(querytype, "cpp"))
+            return EsdlMethodImplCpp;
     }
     }
     return EsdlMethodImplRoxie;
     return EsdlMethodImplRoxie;
 }
 }
@@ -651,6 +710,44 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
 
 
              out.append(finalRespWriter->str());
              out.append(finalRespWriter->str());
         }
         }
+        else if (implType==EsdlMethodImplCpp)
+        {
+            Owned<IXmlWriterExt> reqWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
+
+            //Preprocess Request
+            StringBuffer reqcontent;
+            unsigned xflags = (isPublishedQuery(implType)) ? ROXIEREQ_FLAGS : ESDLREQ_FLAGS;
+            context.addTraceSummaryTimeStamp(LogNormal, "srt-reqproc");
+            m_pEsdlTransformer->process(context, EsdlRequestMode, srvdef.queryName(), mthdef.queryName(), *req, reqWriter.get(), xflags, NULL);
+            context.addTraceSummaryTimeStamp(LogNormal, "end-reqproc");
+
+            reqcontent.set(reqWriter->str());
+            context.addTraceSummaryTimeStamp(LogNormal, "serialized-xmlreq");
+
+            cpp_service_method_t xproc = nullptr;
+            cpp_service_method_t* xprocp = cppProcMap.getValue(mthName);
+            if (xprocp)
+                xproc = *xprocp;
+            if (!xproc)
+                throw makeWsException(ERR_ESDL_BINDING_BADREQUEST, WSERR_SERVER, "ESDL", "C++ plugin or method not loaded for method %s", mthName);
+
+            StringBuffer ctxbuf;
+            ctxbuf.append("<EsdlContext>");
+            if (context.queryUserId())
+                ctxbuf.appendf("<username>%s</username>", context.queryUserId());
+            ctxbuf.append("</EsdlContext>");
+
+            context.addTraceSummaryTimeStamp(LogNormal, "srt-cppcall");
+            xproc(ctxbuf.str(), reqcontent.str(), origResp);
+            context.addTraceSummaryTimeStamp(LogNormal, "end-cppcall");
+
+            context.addTraceSummaryTimeStamp(LogNormal, "srt-procres");
+            Owned<IXmlWriterExt> finalRespWriter = createIXmlWriterExt(0, 0, NULL, (flags & ESDL_BINDING_RESPONSE_JSON) ? WTJSONRootless : WTStandard);
+            m_pEsdlTransformer->processHPCCResult(context, mthdef, origResp.str(), finalRespWriter, logdata, ESDL_TRANS_OUTPUT_ROOT, ns, schema_location);
+            context.addTraceSummaryTimeStamp(LogNormal, "end-procres");
+
+            out.append(finalRespWriter->str());
+        }
         else
         else
         {
         {
             Owned<IXmlWriterExt> reqWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
             Owned<IXmlWriterExt> reqWriter = createIXmlWriterExt(0, 0, NULL, WTStandard);
@@ -2132,7 +2229,7 @@ int EsdlBindingImpl::onJavaPlugin(IEspContext &context,
         try
         try
         {
         {
             Owned<IEsdlDefObjectIterator> it = m_esdl->getDependencies(serviceName, methodName, context.getClientVersion(), context.queryRequestParameters(), 0);
             Owned<IEsdlDefObjectIterator> it = m_esdl->getDependencies(serviceName, methodName, context.getClientVersion(), context.queryRequestParameters(), 0);
-            m_xsdgen->toJavaService( *it, out, EsdlXslToJavaServiceBase, context.queryRequestParameters(), 0);
+            m_xsdgen->toMicroService( *it, out, EsdlXslToJavaServiceBase, context.queryRequestParameters(), 0);
         }
         }
         catch (IException *E)
         catch (IException *E)
         {
         {

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

@@ -31,6 +31,7 @@
 #include "dautils.hpp"
 #include "dautils.hpp"
 #include "esdl_store.hpp"
 #include "esdl_store.hpp"
 #include "esdl_monitor.hpp"
 #include "esdl_monitor.hpp"
+#include "espplugin.ipp"
 
 
 static const char* ESDL_METHOD_DESCRIPTION="description";
 static const char* ESDL_METHOD_DESCRIPTION="description";
 static const char* ESDL_METHOD_HELP="help";
 static const char* ESDL_METHOD_HELP="help";
@@ -65,6 +66,8 @@ static const char* ESDL_METHOD_HELP="help";
 namespace javaembed { IEmbedContext* getEmbedContext(); }
 namespace javaembed { IEmbedContext* getEmbedContext(); }
 #endif
 #endif
 
 
+typedef int (*cpp_service_method_t)(const char* CtxXML, const char* ReqXML, StringBuffer& RespXML);
+
 class EsdlServiceImpl : public CInterface, implements IEspService
 class EsdlServiceImpl : public CInterface, implements IEspService
 {
 {
 private:
 private:
@@ -72,6 +75,8 @@ private:
     MapStringToMyClass<ISmartSocketFactory> connMap;
     MapStringToMyClass<ISmartSocketFactory> connMap;
     MapStringToMyClass<IEmbedServiceContext> javaServiceMap;
     MapStringToMyClass<IEmbedServiceContext> javaServiceMap;
     MapStringToMyClass<IException> javaExceptionMap;
     MapStringToMyClass<IException> javaExceptionMap;
+    MapStringToMyClass<IEspPlugin> cppPluginMap;
+    MapStringTo<cpp_service_method_t, cpp_service_method_t> cppProcMap;
     Owned<ILoggingManager> m_oLoggingManager;
     Owned<ILoggingManager> m_oLoggingManager;
     bool m_bGenerateLocalTrxId;
     bool m_bGenerateLocalTrxId;
     MapStringToMyClass<IEsdlCustomTransform> m_customRequestTransformMap;
     MapStringToMyClass<IEsdlCustomTransform> m_customRequestTransformMap;
@@ -154,6 +159,7 @@ public:
     virtual void init(const IPropertyTree *cfg, const char *process, const char *service);
     virtual void init(const IPropertyTree *cfg, const char *process, const char *service);
     virtual void configureTargets(IPropertyTree *cfg, const char *service);
     virtual void configureTargets(IPropertyTree *cfg, const char *service);
     void configureJavaMethod(const char *method, IPropertyTree &entry, const char *classPath);
     void configureJavaMethod(const char *method, IPropertyTree &entry, const char *classPath);
+    void configureCppMethod(const char *method, IPropertyTree &entry, IEspPlugin*& plugin);
     void configureUrlMethod(const char *method, IPropertyTree &entry);
     void configureUrlMethod(const char *method, IPropertyTree &entry);
     void addServiceLevelRequestTransform(IPropertyTree *customRequestTransform);
     void addServiceLevelRequestTransform(IPropertyTree *customRequestTransform);
     void addMethodLevelRequestTransform(const char *method, IPropertyTree &methodCfg, IPropertyTree *customRequestTransform);
     void addMethodLevelRequestTransform(const char *method, IPropertyTree &methodCfg, IPropertyTree *customRequestTransform);

+ 6 - 0
esp/xslt/CMakeLists.txt

@@ -45,6 +45,12 @@ FOREACH( iFILES
     ${CMAKE_CURRENT_SOURCE_DIR}/esxdl2xsd.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esxdl2xsd.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvbase.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvbase.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvdummy.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/esdl2java_srvdummy.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_srvbasehpp.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_srvbasecpp.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_srvhpp.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_srvcpp.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_cmake.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/esdl2cpp_types.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/roxie_page.xsl
     ${CMAKE_CURRENT_SOURCE_DIR}/roxie_page.xsl
 )
 )
     Install ( FILES ${iFILES} DESTINATION componentfiles/xslt COMPONENT Runtime )
     Install ( FILES ${iFILES} DESTINATION componentfiles/xslt COMPONENT Runtime )

+ 49 - 0
esp/xslt/esdl2cpp_cmake.xslt

@@ -0,0 +1,49 @@
+<?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">
+<xsl:apply-templates select="EsdlService"/>
+</xsl:template>
+
+<xsl:template match="EsdlService">
+    <xsl:variable name="servicename" select="@name"/>
+<xsl:text></xsl:text>cmake_minimum_required(VERSION 3.0)
+project (<xsl:value-of select="$servicename"/>ServicePlugin)
+
+if (("${HPCC_SOURCE_DIR}" STREQUAL "") OR ("${HPCC_BUILD_DIR}" STREQUAL "") OR ("${CMAKE_BUILD_TYPE}" STREQUAL
+ ""))
+    message (FATAL_ERROR "Please specify HPCC_SOURCE_DIR, HPCC_BUILD_DIR and CMAKE_BUILD_TYPE")
+endif ()
+
+set (CMAKE_CXX_FLAGS "-fPIC -std=c++11")
+include_directories ("${HPCC_SOURCE_DIR}/system/jlib"
+                     "${HPCC_SOURCE_DIR}/system/include"
+                     )
+link_directories ("${HPCC_BUILD_DIR}/${CMAKE_BUILD_TYPE}/libs" .)
+
+add_library (<xsl:value-of select="$servicename"/>Service SHARED <xsl:value-of select="$servicename"/>ServiceBase.cpp
+                                       <xsl:value-of select="$servicename"/>ServiceBase.hpp
+                                       <xsl:value-of select="$servicename"/>Service.cpp
+                                       <xsl:value-of select="$servicename"/>Service.hpp
+                                       )
+target_link_libraries (<xsl:value-of select="$servicename"/>Service jlib)<xsl:text>
+</xsl:text>
+</xsl:template>
+</xsl:stylesheet>

+ 356 - 0
esp/xslt/esdl2cpp_srvbasecpp.xslt

@@ -0,0 +1,356 @@
+<?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">
+<xsl:variable name="servicename"><xsl:value-of select="EsdlService/@name"/></xsl:variable>
+<xsl:variable name="servicebase"><xsl:value-of select="$servicename"/>ServiceBase</xsl:variable>
+#include "<xsl:value-of select="$servicename"/>ServiceBase.hpp"
+#include "jliball.hpp"
+#include "jlog.hpp"
+#include "jptree.hpp"
+
+<xsl:apply-templates select="EsdlService"/>
+</xsl:template>
+
+<xsl:template name="outputCppPrimitive">
+        <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="'Double'"/></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="'Integer64'"/></xsl:when>
+            <xsl:when test="$typename='uint64'"><xsl:value-of select="'Integer64'"/></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="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='positiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='base64Binary'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='string'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='xsdString'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='normalizedString'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='binary'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$typename"/></xsl:otherwise>
+        </xsl:choose>
+</xsl:template>
+
+<xsl:template match="EsdlService">
+    <xsl:variable name="servicename" select="@name"/>
+    <xsl:variable name="servicebase"><xsl:value-of select="$servicename"/>ServiceBase</xsl:variable>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>extern "C" int on</xsl:text><xsl:value-of select="../@name"/><xsl:value-of select="@name"/>(const char* CtxStr, const char* ReqStr, StringBuffer&amp; RespStr)
+{
+    Owned&lt;<xsl:value-of select="$servicebase"/>&gt; service = create<xsl:value-of select="$servicename"/>ServiceObj();
+    return service-&gt;<xsl:value-of select="@name"/><xsl:text>(CtxStr, ReqStr, RespStr);
+}
+
+</xsl:text>
+        </xsl:for-each>
+
+<xsl:text>
+class </xsl:text><xsl:value-of select="$servicename"/>UnSerializer : public CInterface, implements IInterface
+{
+public:
+    IMPLEMENT_IINTERFACE;
+
+    <xsl:value-of select="$servicename"/>UnSerializer()
+    {
+    }
+
+    int unserialize(EsdlContext* obj, IPropertyTree* ptree)
+    {
+        if (!obj || !ptree)
+            return 0;
+        if (ptree->hasProp("username"))
+            obj->username.setown(new PString(ptree->queryProp("username")));
+        if (ptree->hasProp("clientMajorVersion"))
+            obj->clientMajorVersion.setown(new Integer(ptree->getPropInt("clientMajorVersion")));
+        if (ptree->hasProp("clientMinorVersion"))
+            obj->clientMinorVersion.setown(new Integer(ptree->getPropInt("clientMinorVersion")));
+    }<xsl:text>
+</xsl:text>
+
+    <xsl:for-each select="/esxdl/EsdlRequest|/esxdl/EsdlResponse|/esxdl/EsdlStruct">
+        <xsl:call-template name="generateUnserializeForStruct"/>
+    </xsl:for-each>
+
+    <xsl:for-each select="/esxdl/EsdlRequest|/esxdl/EsdlResponse|/esxdl/EsdlStruct">
+        <xsl:call-template name="generateSerializeForStruct"/>
+    </xsl:for-each>
+<xsl:text>
+};
+</xsl:text>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>int </xsl:text><xsl:value-of select="$servicebase"/>::<xsl:value-of select="@name"/><xsl:text>(const char* CtxStr, const char* ReqStr, StringBuffer&amp; RespStr)
+{</xsl:text>
+    Owned&lt;<xsl:value-of select="$servicename"/>UnSerializer&gt; UnSe = new <xsl:value-of select="$servicename"/>UnSerializer();
+    Owned&lt;EsdlContext&gt; ctx = new EsdlContext();
+    if (CtxStr &amp;&amp; *CtxStr)
+    {
+        Owned&lt;IPropertyTree&gt; ptree = createPTreeFromXMLString(CtxStr);
+        UnSe-&gt;unserialize(ctx.get(), ptree.get());
+    }
+    Owned&lt;<xsl:value-of select="$servicebase"/>&gt; service = create<xsl:value-of select="$servicename"/>ServiceObj();
+    Owned&lt;<xsl:value-of select="@request_type"/>&gt; req = new <xsl:value-of select="@request_type"/>();
+    Owned&lt;IPropertyTree&gt; ptree;
+    ptree.setown(createPTreeFromXMLString(ReqStr));
+    UnSe->unserialize(req.get(), ptree.get());
+    Owned&lt;<xsl:value-of select="@response_type"/>&gt; resp = service-&gt;<xsl:value-of select="@name"/>(ctx.get(), req.get());
+    RespStr = "&lt;Response&gt;&lt;Results&gt;&lt;Result&gt;&lt;Dataset name=\"<xsl:value-of select="@response_type"/>\">&lt;Row&gt;";
+    UnSe->serialize(resp.get(), RespStr);
+    RespStr.append("&lt;/Row&gt;&lt;/Dataset&gt;&lt;/Result&gt;&lt;/Results&gt;&lt;/Response&gt;");
+
+    return 0;
+}<xsl:text>
+</xsl:text>
+    </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="generateUnserializeForStruct">
+    int unserialize(<xsl:value-of select="@name"/>* obj, IPropertyTree* ptree)
+    {
+        if (!obj || !ptree)
+            return 0;
+        IPropertyTree* subtree = nullptr;<xsl:text>
+
+</xsl:text>
+        <xsl:for-each select="*">
+        <xsl:variable name="fieldclass" select="name(.)"/>
+        <xsl:variable name="fieldname"  select="@name"/>
+        <xsl:variable name="fieldvar"  select="concat('m_', $fieldname)"/>
+        <xsl:choose>
+            <xsl:when test="$fieldclass='EsdlElement'">
+            <xsl:choose>
+                <xsl:when test="@complex_type">
+        subtree = ptree->queryPropTree("<xsl:value-of select="$fieldname"/>");
+        if (subtree != nullptr)
+        {
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new <xsl:value-of select="@complex_type"/>());
+            unserialize(obj-&gt;<xsl:value-of select="$fieldvar"/>.get(), subtree);
+        }<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:otherwise>
+                    <xsl:variable name="primitive">
+                        <xsl:call-template name="outputCppPrimitive">
+                           <xsl:with-param name="typename">
+                              <xsl:value-of select="@type"/>
+                           </xsl:with-param>
+                        </xsl:call-template>
+                    </xsl:variable>
+                    <xsl:choose>
+                    <xsl:when test="$primitive='PString'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new PString(ptree-&gt;queryProp("<xsl:value-of select="$fieldname"/>")));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:when test="$primitive='Integer'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new Integer(ptree-&gt;getPropInt("<xsl:value-of select="$fieldname"/>")));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:when test="$primitive='Integer64'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new Integer64(ptree-&gt;getPropInt64("<xsl:value-of select="$fieldname"/>")));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:when test="$primitive='Boolean'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new Boolean(ptree-&gt;getPropBool("<xsl:value-of select="$fieldname"/>")));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:when test="$primitive='Float'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new Float(atof(ptree-&gt;queryProp("<xsl:value-of select="$fieldname"/>"))));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:when test="$primitive='Double'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/>.setown(new Double(atof(ptree-&gt;queryProp("<xsl:value-of select="$fieldname"/>"))));<xsl:text>
+</xsl:text>
+                    </xsl:when>
+                    <xsl:otherwise>
+                    </xsl:otherwise>
+                    </xsl:choose>
+                </xsl:otherwise>
+            </xsl:choose>
+            </xsl:when>
+            <xsl:when test="$fieldclass='EsdlArray'">
+        subtree = ptree->queryPropTree("<xsl:value-of select="$fieldname"/>");
+        if (subtree != nullptr)
+        {
+            Owned&lt;IPropertyTreeIterator&gt; itr = subtree->getElements("<xsl:value-of select="@item_tag"/>");
+            ForEach (*itr)
+            {
+                IPropertyTree* onetree = &amp;itr->query();<xsl:text>
+</xsl:text>
+            <xsl:variable name="primitive">
+                <xsl:call-template name="outputCppPrimitive">
+                   <xsl:with-param name="typename">
+                      <xsl:value-of select="@type"/>
+                   </xsl:with-param>
+                </xsl:call-template>
+            </xsl:variable>
+            <xsl:choose>
+                <xsl:when test="$primitive=@type">
+                Owned&lt;<xsl:value-of select="@type"/>&gt; oneobj(new <xsl:value-of select="@type"/>());
+                unserialize(oneobj.get(), onetree);
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*oneobj.getClear());<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='PString'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new PString(onetree->queryProp("."))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='Integer'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new Integer(onetree->getPropInt("."))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='Integer64'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new Integer64(onetree->getPropInt64("."))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='Boolean'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new Boolean(onetree->getPropBool("."))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='Float'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new Float(atof(onetree->queryProp(".")))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:when test="$primitive='Double'">
+                obj-&gt;<xsl:value-of select="$fieldvar"/>.append(*(new Double(atof(onetree->queryProp(".")))));<xsl:text>
+</xsl:text>
+                </xsl:when>
+            </xsl:choose>
+            }<xsl:text>
+</xsl:text>
+         }<xsl:text>
+</xsl:text>
+            </xsl:when>
+            <xsl:when test="$fieldclass='EsdlEnum'">
+        if (ptree-&gt;hasProp("<xsl:value-of select="$fieldname"/>"))
+            obj-&gt;<xsl:value-of select="$fieldvar"/> = EnumHandler<xsl:value-of select="@enum_type"/>::fromString(ptree-&gt;queryProp("<xsl:value-of select="$fieldname"/>"));<xsl:text>
+</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+            </xsl:otherwise>
+        </xsl:choose>
+        </xsl:for-each>
+        return 0;
+    }
+</xsl:template>
+
+<xsl:template name="generateSerializeForStruct">
+    int serialize(<xsl:value-of select="@name"/>* obj, StringBuffer&amp; buf)
+    {
+        if (!obj)
+            return 0;<xsl:text>
+</xsl:text>
+        <xsl:for-each select="*">
+        <xsl:variable name="fieldclass" select="name(.)"/>
+        <xsl:variable name="fieldname"  select="@name"/>
+        <xsl:variable name="fieldvar"  select="concat('m_', $fieldname)"/>
+        <xsl:choose>
+            <xsl:when test="$fieldclass='EsdlElement'">
+        if (obj-&gt;<xsl:value-of select="$fieldvar"/>)
+        {
+            buf.append("&lt;<xsl:value-of select="$fieldname"/>&gt;");<xsl:text>
+</xsl:text>
+            <xsl:choose>
+                <xsl:when test="@complex_type">
+<xsl:text>            </xsl:text>serialize(obj-&gt;<xsl:value-of select="$fieldvar"/>, buf);<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:otherwise>
+                    <xsl:variable name="primitive">
+                        <xsl:call-template name="outputCppPrimitive">
+                           <xsl:with-param name="typename">
+                              <xsl:value-of select="@type"/>
+                           </xsl:with-param>
+                        </xsl:call-template>
+                    </xsl:variable>
+<xsl:text>            </xsl:text>buf.append(obj-&gt;<xsl:value-of select="$fieldvar"/>-&gt;str());<xsl:text>
+</xsl:text>
+                </xsl:otherwise>
+            </xsl:choose>
+<xsl:text>            </xsl:text>buf.append("&lt;/<xsl:value-of select="$fieldname"/>&gt;");<xsl:text>
+        }
+</xsl:text>
+            </xsl:when>
+            <xsl:when test="$fieldclass='EsdlArray'">
+        if (obj-&gt;<xsl:value-of select="$fieldvar"/>.length() > 0)
+        {
+            buf.append("&lt;<xsl:value-of select="$fieldname"/>&gt;");
+            ForEachItemIn(i, obj-&gt;<xsl:value-of select="$fieldvar"/>)
+            {<xsl:text>
+</xsl:text>
+            <xsl:variable name="primitive">
+                <xsl:call-template name="outputCppPrimitive">
+                   <xsl:with-param name="typename">
+                      <xsl:value-of select="@type"/>
+                   </xsl:with-param>
+                </xsl:call-template>
+            </xsl:variable>
+            <xsl:choose>
+                <xsl:when test="$primitive=@type">
+                <xsl:text>                    </xsl:text><xsl:value-of select="@type"/>&amp; oneitem = obj-&gt;<xsl:value-of select="$fieldvar"/>.item(i);
+                buf.append("&lt;<xsl:value-of select="@item_tag"/>&gt;");
+                serialize(&amp;oneitem, buf);
+                buf.append("&lt;/<xsl:value-of select="@item_tag"/>&gt;");<xsl:text>
+</xsl:text>
+                </xsl:when>
+                <xsl:otherwise>
+                <xsl:text>            </xsl:text><xsl:value-of select="$primitive"/>&amp; oneitem = obj-&gt;<xsl:value-of select="$fieldvar"/>.item(i);
+                buf.append("&lt;<xsl:value-of select="@item_tag"/>&gt;").append(oneitem.str()).append("&lt;/<xsl:value-of select="@item_tag"/>&gt;");<xsl:text>
+</xsl:text>
+                </xsl:otherwise>
+            </xsl:choose>
+            }
+            buf.append("&lt;/<xsl:value-of select="$fieldname"/>&gt;");
+        }<xsl:text>
+</xsl:text>
+            </xsl:when>
+            <xsl:when test="$fieldclass='EsdlEnum'">
+        if (obj-&gt;<xsl:value-of select="$fieldvar"/> != <xsl:value-of select="@enum_type"/>::UNSET)
+            buf.append("&lt;<xsl:value-of select="$fieldname"/>&gt;").append(EnumHandler<xsl:value-of select="@enum_type"/>::toString(obj-&gt;<xsl:value-of select="$fieldvar"/>)).append("&lt;/<xsl:value-of select="$fieldname"/>&gt;");<xsl:text>
+</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+            </xsl:otherwise>
+        </xsl:choose>
+        </xsl:for-each>
+        return 0;
+    }<xsl:text>
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>

+ 273 - 0
esp/xslt/esdl2cpp_srvbasehpp.xslt

@@ -0,0 +1,273 @@
+<?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">
+<xsl:variable name="servicename"><xsl:value-of select="EsdlService/@name"/></xsl:variable>
+<xsl:variable name="upperService"><xsl:value-of select="translate(EsdlService/@name, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:variable>
+<xsl:text>#ifndef </xsl:text><xsl:value-of select="$upperService"/>SERVICEBASE_HPP__
+<xsl:text>#define </xsl:text><xsl:value-of select="$upperService"/>SERVICEBASE_HPP__
+
+#include "jlib.hpp"
+#include "jptree.hpp"
+#include "jarray.hpp"
+#include "primitivetypes.hpp"
+
+using namespace std;
+using namespace cppplugin;
+
+class EsdlContext : public CInterface, implements IInterface
+{
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Owned&lt;PString&gt; username;
+    Owned&lt;Integer&gt; clientMajorVersion;
+    Owned&lt;Integer&gt; 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"/>
+// User need to implement this function
+extern "C" <xsl:value-of select="$servicename"/>ServiceBase* create<xsl:value-of select="$servicename"/>ServiceObj();
+
+<xsl:text>
+#endif</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlStruct|EsdlRequest|EsdlResponse">
+class <xsl:value-of select="@name"/><xsl:choose><xsl:when test="@base_type"> : public <xsl:value-of select="@base_type"/></xsl:when><xsl:otherwise> : public CInterface, implements IInterface</xsl:otherwise></xsl:choose>
+{
+public:
+    IMPLEMENT_IINTERFACE;
+
+<xsl:apply-templates select="EsdlElement|EsdlArray|EsdlEnum"/><xsl:text>};
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template name="outputCppPrimitive">
+        <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="'Double'"/></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="'Integer64'"/></xsl:when>
+            <xsl:when test="$typename='uint64'"><xsl:value-of select="'Integer64'"/></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="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='positiveInteger'"><xsl:value-of select="'Integer'"/></xsl:when>
+            <xsl:when test="$typename='base64Binary'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='string'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='xsdString'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='normalizedString'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:when test="$typename='binary'"><xsl:value-of select="'PString'"/></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$typename"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+    <xsl:template match="EsdlArray">
+        <xsl:variable name="mytype"><xsl:value-of select="@type"/></xsl:variable>
+        <xsl:variable name="primitive">
+            <xsl:call-template name="outputCppPrimitive">
+               <xsl:with-param name="typename">
+                  <xsl:value-of select="@type"/>
+               </xsl:with-param>
+            </xsl:call-template>
+        </xsl:variable>
+            <xsl:text>    </xsl:text>
+            <xsl:text>IArrayOf&lt;</xsl:text>
+        <xsl:value-of select="$primitive"/><xsl:text>&gt; </xsl:text>m_<xsl:value-of select="@name"/>;<xsl:text>
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlElement">
+        <xsl:variable name="primitive">
+            <xsl:call-template name="outputCppPrimitive">
+               <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>    </xsl:text>
+        <xsl:text>Owned&lt;</xsl:text>
+    <xsl:value-of select="$primitive"/>
+        <xsl:text>&gt;</xsl:text>
+        <xsl:text> </xsl:text>
+        <xsl:text>m_</xsl:text><xsl:value-of select="@name"/>
+        <xsl:choose>
+            <xsl:when test="@default">
+        <xsl:text> = new </xsl:text><xsl:value-of select="$primitive"/><xsl:text>(</xsl:text>
+            <xsl:choose>
+                <xsl:when test="$primitive='PString'">"<xsl:value-of select="@default"/>"</xsl:when>
+                <xsl:when test="$primitive='bool'">
+            <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="outputCppPrimitive">
+               <xsl:with-param name="typename">
+                     <xsl:value-of select="@enum_type"/>
+               </xsl:with-param>
+            </xsl:call-template>
+        </xsl:variable>
+        <xsl:text>    </xsl:text>
+    <xsl:value-of select="$primitive"/>
+        <xsl:text> </xsl:text>
+        <xsl:text>m_</xsl:text><xsl:value-of select="@name"/>
+            <xsl:choose>
+            <xsl:when test="@default">
+                <xsl:text> = EnumHandler</xsl:text><xsl:value-of select="$primitive"/>::fromString<xsl:text>(</xsl:text>"<xsl:value-of select="@default"/><xsl:text>")</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:text> = </xsl:text><xsl:value-of select="$primitive"/><xsl:text>::UNSET</xsl:text>
+            </xsl:otherwise>
+            </xsl:choose>
+        <xsl:text>;
+</xsl:text>
+    </xsl:template>
+
+    <xsl:template match="EsdlService">
+class <xsl:value-of select="@name"/>ServiceBase : public CInterface, implements IInterface
+{
+public:
+    IMPLEMENT_IINTERFACE;<xsl:text>
+</xsl:text>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>    virtual </xsl:text><xsl:value-of select="@response_type"/>*<xsl:text> </xsl:text><xsl:value-of select="@name"/>(EsdlContext* context, <xsl:value-of select="@request_type"/><xsl:text>* request){return nullptr;}
+</xsl:text>
+    </xsl:for-each>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>    </xsl:text><xsl:text>virtual int </xsl:text><xsl:value-of select="@name"/><xsl:text>(const char* CtxStr, const char* ReqStr, StringBuffer&amp; RespStr);
+</xsl:text>
+    </xsl:for-each>
+<xsl:text>};
+
+</xsl:text>
+<xsl:text>// Implemented in generated code
+</xsl:text>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>extern "C" int on</xsl:text><xsl:value-of select="../@name"/><xsl:value-of select="@name"/><xsl:text>(const char* CtxStr, const char* ReqStr, StringBuffer&amp; RespStr);
+</xsl:text>
+        </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template match="EsdlEnumType">
+      <xsl:if test="EsdlEnumItem">
+enum class <xsl:value-of select="@name"/><xsl:text>
+{
+    UNSET = 0,
+</xsl:text>
+        <xsl:for-each select="EsdlEnumItem">
+          <xsl:text>    </xsl:text><xsl:value-of select="@name"/>
+           <xsl:choose>
+             <xsl:when test="position() != last()">
+              <xsl:text>,
+</xsl:text>
+             </xsl:when>
+             <xsl:otherwise>
+             </xsl:otherwise>
+           </xsl:choose>
+        </xsl:for-each>
+        <xsl:text>
+};
+</xsl:text>
+
+class EnumHandler<xsl:value-of select="@name"/>
+{
+public:
+    static <xsl:value-of select="@name"/> fromString(const char* str)
+    {
+        <xsl:for-each select="EsdlEnumItem">
+        <xsl:choose>
+            <xsl:when test="position() = 1">
+                <xsl:text>if (strcmp(str, "</xsl:text><xsl:value-of select="@enum"/><xsl:text>") == 0)
+</xsl:text>
+            </xsl:when>
+            <xsl:when test="position() = last()">
+                <xsl:text>        else
+</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:text>        else if (strcmp(str, "</xsl:text><xsl:value-of select="@enum"/><xsl:text>") == 0)
+</xsl:text>
+            </xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>            return </xsl:text><xsl:value-of select="../@name"/>::<xsl:value-of select="@name"/><xsl:text>;
+</xsl:text>
+        </xsl:for-each>
+    }
+
+    static const char* toString(<xsl:value-of select="@name"/> val)
+    {
+        <xsl:for-each select="EsdlEnumItem">
+        <xsl:choose>
+            <xsl:when test="position() = 1">
+                <xsl:text>if (val == </xsl:text><xsl:value-of select="../@name"/>::<xsl:value-of select="@name"/><xsl:text>)
+</xsl:text>
+            </xsl:when>
+            <xsl:when test="position() = last()">
+                <xsl:text>        else
+</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:text>        else if (val == </xsl:text><xsl:value-of select="../@name"/>::<xsl:value-of select="@name"/><xsl:text>)
+</xsl:text>
+            </xsl:otherwise>
+        </xsl:choose>
+        <xsl:text>            return "</xsl:text><xsl:value-of select="@enum"/><xsl:text>";
+</xsl:text>
+        </xsl:for-each>
+    }
+};
+</xsl:if>
+    </xsl:template>
+</xsl:stylesheet>

+ 52 - 0
esp/xslt/esdl2cpp_srvcpp.xslt

@@ -0,0 +1,52 @@
+<?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">
+<xsl:variable name="servicename"><xsl:value-of select="EsdlService/@name"/></xsl:variable>
+<xsl:text>#include "</xsl:text><xsl:value-of select="$servicename"/>Service.hpp"
+#include "jliball.hpp"
+#include "jlog.hpp"
+#include "jptree.hpp"
+
+<xsl:apply-templates select="EsdlService"/>
+
+<xsl:text>extern "C" </xsl:text><xsl:value-of select="$servicename"/>ServiceBase* create<xsl:value-of select="$servicename"/>ServiceObj()
+{
+    return new <xsl:value-of select="$servicename"/>Service();
+}<xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template match="EsdlService">
+    <xsl:variable name="servicename" select="@name"/>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:value-of select="@response_type"/>* <xsl:value-of select="$servicename"/>Service::<xsl:value-of select="@name"/>(EsdlContext* context, <xsl:value-of select="@request_type"/>* request)
+{
+    Owned&lt;<xsl:value-of select="@response_type"/>&gt; resp = new <xsl:value-of select="@response_type"/>();
+    //Fill in logic
+    return resp.getClear();
+}<xsl:text>
+
+</xsl:text>
+    </xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>

+ 58 - 0
esp/xslt/esdl2cpp_srvhpp.xslt

@@ -0,0 +1,58 @@
+<?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">
+<xsl:variable name="servicename"><xsl:value-of select="EsdlService/@name"/></xsl:variable>
+<xsl:variable name="upperService"><xsl:value-of select="translate(EsdlService/@name, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:variable>
+<xsl:text>#ifndef </xsl:text><xsl:value-of select="$upperService"/>SERVICE_HPP__
+<xsl:text>#define </xsl:text><xsl:value-of select="$upperService"/>SERVICE_HPP__
+
+#include "jlib.hpp"
+#include "<xsl:value-of select="$servicename"/>ServiceBase.hpp"
+
+using namespace std;
+
+<xsl:apply-templates select="EsdlService"/>
+#endif
+</xsl:template>
+
+<xsl:template match="EsdlService">
+    <xsl:variable name="servicename" select="@name"/>
+class <xsl:value-of select="$servicename"/>Service : public <xsl:value-of select="$servicename"/>ServiceBase
+{
+public:
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>    virtual </xsl:text><xsl:value-of select="@response_type"/>*<xsl:text> </xsl:text><xsl:value-of select="@name"/>(EsdlContext* context, <xsl:value-of select="@request_type"/><xsl:text>* request);
+</xsl:text>
+    </xsl:for-each>
+    <xsl:for-each select="EsdlMethod">
+    <xsl:text>    </xsl:text><xsl:text>virtual int </xsl:text><xsl:value-of select="@name"/>(const char* CtxStr, const char* ReqStr, StringBuffer&amp; RespStr)
+    {
+        return <xsl:value-of select="$servicename"/>ServiceBase::<xsl:value-of select="@name"/>(CtxStr, ReqStr, RespStr);
+    }<xsl:text>
+</xsl:text>
+    </xsl:for-each>
+<xsl:text>};
+</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>

+ 225 - 0
esp/xslt/esdl2cpp_types.xslt

@@ -0,0 +1,225 @@
+<?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:output>
+<xsl:template match="esxdl">
+<xsl:text>#ifndef PRIMITIVE_TYPES_HPP__
+#define PRIMITIVE_TYPES_HPP__
+
+#include "jlib.hpp"
+#include "jstring.hpp"
+#include &lt;string&gt;
+
+using namespace std;
+
+namespace cppplugin
+{
+
+class Integer : public CInterface, implements IInterface
+{
+private:
+    int v;
+    StringBuffer s;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Integer(int v_)
+    {
+        v = v_;
+        s.appendf("%d", v_);
+    }
+
+    int val()
+    {
+        return v;
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(s);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return s;
+    }
+};
+
+class Integer64 : public CInterface, implements IInterface
+{
+private:
+    int64_t v;
+    StringBuffer s;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Integer64(int64_t v_)
+    {
+        v = v_;
+        s.appendf("%ld", v_);
+    }
+
+    int64_t val()
+    {
+        return v;
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(s);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return s;
+    }
+};
+
+class Float : public CInterface, implements IInterface
+{
+private:
+    float v;
+    StringBuffer s;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Float(float v_)
+    {
+        v = v_;
+        s.appendf("%f", v_);
+    }
+
+    float val()
+    {
+        return v;
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(s);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return s;
+    }
+};
+
+class Double : public CInterface, implements IInterface
+{
+private:
+    double v;
+    StringBuffer s;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Double(double v_)
+    {
+        v = v_;
+        s.appendf("%f", v_);
+    }
+
+    double val()
+    {
+        return v;
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(s);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return s;
+    }
+};
+
+class Boolean : public CInterface, implements IInterface
+{
+private:
+    bool v;
+    StringBuffer s;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    Boolean(bool v_)
+    {
+        v = v_;
+        s.appendf("%s", v_?"true":"false");
+    }
+
+    bool val()
+    {
+        return v;
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(s);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return s;
+    }
+};
+
+class PString : public CInterface, implements IInterface
+{
+private:
+    StringBuffer v;
+public:
+    IMPLEMENT_IINTERFACE;
+
+    PString(const char* v_)
+    {
+        v.append(v_);
+    }
+
+    PString(size32_t len, const char* v_)
+    {
+        v.append(len, v_);
+    }
+
+    const char* val()
+    {
+        return v.str();
+    }
+
+    StringBuffer&amp; str(StringBuffer&amp; buf)
+    {
+        buf.append(v);
+        return buf;
+    }
+
+    StringBuffer&amp; str()
+    {
+        return v;
+    }
+};
+}
+#endif</xsl:text>
+</xsl:template>
+</xsl:stylesheet>

+ 44 - 0
initfiles/examples/EsdlExample/CppPlugin/EsdlExampleService.cpp

@@ -0,0 +1,44 @@
+#include "EsdlExampleService.hpp"
+#include "jliball.hpp"
+#include "jlog.hpp"
+#include "jptree.hpp"
+
+CppEchoPersonInfoResponse* EsdlExampleService::CppEchoPersonInfo(EsdlContext* context, CppEchoPersonInfoRequest* request)
+{
+    Owned<CppEchoPersonInfoResponse> resp = new CppEchoPersonInfoResponse();
+    //Fill in logic
+    resp->count.setown(new Integer(0));
+    if(request->Name)
+    {
+        resp->count.setown(new Integer(1));
+        resp->Name.set(request->Name.get());
+    }
+    appendArray(resp->Addresses, request->Addresses);
+    return resp.getClear();
+}
+
+JavaEchoPersonInfoResponse* EsdlExampleService::JavaEchoPersonInfo(EsdlContext* context, JavaEchoPersonInfoRequest* request)
+{
+    Owned<JavaEchoPersonInfoResponse> resp = new JavaEchoPersonInfoResponse();
+    //Fill in logic
+    return resp.getClear();
+}
+
+EsdlExamplePingResponse* EsdlExampleService::Ping(EsdlContext* context, EsdlExamplePingRequest* request)
+{
+    Owned<EsdlExamplePingResponse> resp = new EsdlExamplePingResponse();
+    //Fill in logic
+    return resp.getClear();
+}
+
+RoxieEchoPersonInfoResponse* EsdlExampleService::RoxieEchoPersonInfo(EsdlContext* context, RoxieEchoPersonInfoRequest* request)
+{
+    Owned<RoxieEchoPersonInfoResponse> resp = new RoxieEchoPersonInfoResponse();
+    //Fill in logic
+    return resp.getClear();
+}
+
+extern "C" EsdlExampleServiceBase* createEsdlExampleServiceObj()
+{
+    return new EsdlExampleService();
+}

+ 36 - 0
initfiles/examples/EsdlExample/CppPlugin/ReadMeFirst.txt

@@ -0,0 +1,36 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 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.
+############################################################################## */
+
+From EsdlExample copy folder:
+
+1. Generate c++ files (which will be put under cpptest folder):
+esdl cpp esdl_example.esdl EsdlExample --outdir cpptest
+
+2. Change to build diretory
+cd cpptest/build
+
+3. Run cmake
+cmake ../source/ -DHPCC_SOURCE_DIR=/home/mayx/git/HPCC-Platform -DHPCC_BUILD_DIR=/home/mayx/git/ecbuild -DCMAK
+E_BUILD_TYPE=Debug -G"Eclipse CDT4 - Unix Makefiles"
+
+4. Compile, the plugin shared object will be created
+make -j8
+
+5. Copy the plugin SO to the "plugins" folder under your HPCC running directory
+
+6. Bind service with the config similar to the following
+    <Method name="CppEchoPersonInfo" querytype="cpp" method="onEsdlExampleCppEchoPersonInfo" plugin="libEsdlExampleService.so"/>

+ 3 - 0
initfiles/examples/EsdlExample/CppPlugin/cpp_binding.xml

@@ -0,0 +1,3 @@
+ <Methods>
+    <Method name="CppEchoPersonInfo" querytype="cpp" method="onEsdlExampleCppEchoPersonInfo" plugin="libEsdlExampleService.so"/>
+</Methods>

+ 11 - 0
initfiles/examples/EsdlExample/CppPlugin/main.cpp

@@ -0,0 +1,11 @@
+#include "EsdlExampleService.hpp"
+#include "jliball.hpp"
+
+int main(int argc, char** argv)
+{
+    InitModuleObjects();
+    StringBuffer result;
+    onEsdlExampleCppEchoPersonInfo("", "<CppEchoPersonInfoRequest><Name><First>Joe</First><Last>Doe</Last><Aliases><Alias>JD</Alias></Aliases></Name><Addresses><Address><Line1>6601 Park of Commerce Blvd</Line1><City>Boca Raton</City><State>FL</State><Zip>33487</Zip></Address></Addresses></CppEchoPersonInfoRequest>", result);
+    DBGLOG("%s", result.str());
+    return 0;
+}

+ 1 - 0
initfiles/examples/EsdlExample/CppPlugin/runcmake.sh

@@ -0,0 +1 @@
+cmake ../source/ -DHPCC_SOURCE_DIR=/home/mayx/git/HPCC-Platform -DHPCC_BUILD_DIR=/home/mayx/git/build -DCMAKE_BUILD_TYPE=Debug -G"Eclipse CDT4 - Unix Makefiles"

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

@@ -10,6 +10,7 @@
           </xsdl:choose>
           </xsdl:choose>
        </xsdl:CustomRequestTransform>
        </xsdl:CustomRequestTransform>
     <Method name="JavaEchoPersonInfo" querytype="java" javamethod="EsdlExample.EsdlExampleService.JavaEchoPersonInfo"/>
     <Method name="JavaEchoPersonInfo" querytype="java" javamethod="EsdlExample.EsdlExampleService.JavaEchoPersonInfo"/>
+    <Method name="CppEchoPersonInfo" querytype="cpp" method="onEsdlExampleCppEchoPersonInfo" plugin="libEsdlExampleService.so"/>
     <Method name="RoxieEchoPersonInfo" querytype="roxie" url="http://localhost:9876/roxie" queryname="RoxieEchoPersonInfo">
     <Method name="RoxieEchoPersonInfo" querytype="roxie" url="http://localhost:9876/roxie" queryname="RoxieEchoPersonInfo">
          <xsdl:CustomRequestTransform target="soap:Body/{$query}">
          <xsdl:CustomRequestTransform target="soap:Body/{$query}">
             <xsdl:choose>
             <xsdl:choose>

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

@@ -41,6 +41,19 @@ ESPStruct AddressInfo
     int Zip(33487);  
     int Zip(33487);  
 };
 };
 
 
+ESPrequest CppEchoPersonInfoRequest
+{
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
+ESPresponse CppEchoPersonInfoResponse
+{
+     int count(0);
+     ESPstruct NameInfo Name;
+     ESParray<ESPstruct AddressInfo, Address> Addresses;
+};
+
 ESPrequest JavaEchoPersonInfoRequest
 ESPrequest JavaEchoPersonInfoRequest
 {
 {
      ESPstruct NameInfo Name;
      ESPstruct NameInfo Name;
@@ -69,6 +82,7 @@ ESPresponse RoxieEchoPersonInfoResponse
 
 
 ESPservice [version("0.01")] EsdlExample
 ESPservice [version("0.01")] EsdlExample
 {
 {
+    ESPmethod CppEchoPersonInfo(CppEchoPersonInfoRequest, CppEchoPersonInfoResponse);
     ESPmethod JavaEchoPersonInfo(JavaEchoPersonInfoRequest, JavaEchoPersonInfoResponse);
     ESPmethod JavaEchoPersonInfo(JavaEchoPersonInfoRequest, JavaEchoPersonInfoResponse);
     ESPmethod RoxieEchoPersonInfo(RoxieEchoPersonInfoRequest, RoxieEchoPersonInfoResponse);
     ESPmethod RoxieEchoPersonInfo(RoxieEchoPersonInfoRequest, RoxieEchoPersonInfoResponse);
 };
 };

+ 316 - 2
tools/esdlcmd/esdlcmd_core.cpp

@@ -707,7 +707,7 @@ public:
         StringBuffer xsltpathServiceBase(optXsltPath);
         StringBuffer xsltpathServiceBase(optXsltPath);
         xsltpathServiceBase.append(XSLT_ESDL2JAVABASE);
         xsltpathServiceBase.append(XSLT_ESDL2JAVABASE);
         cmdHelper.defHelper->loadTransform( xsltpathServiceBase, NULL, EsdlXslToJavaServiceBase);
         cmdHelper.defHelper->loadTransform( xsltpathServiceBase, NULL, EsdlXslToJavaServiceBase);
-        cmdHelper.defHelper->toJavaService( *structs, outputBuffer, EsdlXslToJavaServiceBase, NULL, optFlags );
+        cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToJavaServiceBase, NULL, optFlags );
 
 
         VStringBuffer javaFileNameBase("%sServiceBase.java", optService.get());
         VStringBuffer javaFileNameBase("%sServiceBase.java", optService.get());
         saveAsFile(".", javaFileNameBase, outputBuffer.str(), NULL);
         saveAsFile(".", javaFileNameBase, outputBuffer.str(), NULL);
@@ -715,7 +715,7 @@ public:
         StringBuffer xsltpathServiceDummy(optXsltPath);
         StringBuffer xsltpathServiceDummy(optXsltPath);
         xsltpathServiceDummy.append(XSLT_ESDL2JAVADUMMY);
         xsltpathServiceDummy.append(XSLT_ESDL2JAVADUMMY);
         cmdHelper.defHelper->loadTransform( xsltpathServiceDummy, NULL, EsdlXslToJavaServiceDummy);
         cmdHelper.defHelper->loadTransform( xsltpathServiceDummy, NULL, EsdlXslToJavaServiceDummy);
-        cmdHelper.defHelper->toJavaService( *structs, outputBuffer.clear(), EsdlXslToJavaServiceDummy, NULL, optFlags );
+        cmdHelper.defHelper->toMicroService( *structs, outputBuffer.clear(), EsdlXslToJavaServiceDummy, NULL, optFlags );
 
 
         VStringBuffer javaFileNameDummy("%sServiceDummy.java", optService.get());
         VStringBuffer javaFileNameDummy("%sServiceDummy.java", optService.get());
         saveAsFile(".", javaFileNameDummy, outputBuffer.str(), NULL);
         saveAsFile(".", javaFileNameDummy, outputBuffer.str(), NULL);
@@ -801,6 +801,318 @@ protected:
     Owned<IProperties> params;
     Owned<IProperties> params;
 };
 };
 
 
+#define XSLT_ESDL2CPPBASEHPP "esdl2cpp_srvbasehpp.xslt"
+#define XSLT_ESDL2CPPBASECPP "esdl2cpp_srvbasecpp.xslt"
+#define XSLT_ESDL2CPPSRVHPP "esdl2cpp_srvhpp.xslt"
+#define XSLT_ESDL2CPPSRVCPP "esdl2cpp_srvcpp.xslt"
+#define XSLT_ESDL2CPPCMAKE "esdl2cpp_cmake.xslt"
+#define XSLT_ESDL2CPPTYPES "esdl2cpp_types.xslt"
+
+class Esdl2CppCmd : public EsdlHelperConvertCmd
+{
+public:
+    Esdl2CppCmd() : 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(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(optOutDirPath, ESDL_CONVERT_OUTDIR))
+            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)
+    {
+        extractEsdlCmdOption(optIncludePath, globals, ESDLOPT_INCLUDE_PATH_ENV, ESDLOPT_INCLUDE_PATH_INI, NULL, NULL);
+
+        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 (!optXsltPath.length())
+        {
+            StringBuffer binXsltPath;
+            getComponentFilesRelPathFromBin(binXsltPath);
+            binXsltPath.append("/xslt/");
+            StringBuffer temp;
+            if (checkFileExists(temp.append(binXsltPath).append(XSLT_ESDL2CPPBASEHPP)))
+                optXsltPath.set(binXsltPath);
+            else
+                optXsltPath.set(temp.set(COMPONENTFILES_DIR).append("/xslt/"));
+        }
+        cmdHelper.verbose = optVerbose;
+        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, 0, optIncludePath);
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, 0, NULL, optFlags );
+
+        if(!optPreprocessOutputDir.isEmpty())
+        {
+            outputRaw(*structs);
+        }
+
+
+        StringBuffer outdir;
+        if (optOutDirPath.length() > 0)
+            outdir.append(optOutDirPath);
+        else
+            outdir.append(".");
+        StringBuffer sourcedir(outdir);
+        sourcedir.append(PATHSEPCHAR).append("source");
+        StringBuffer builddir(outdir);
+        builddir.append(PATHSEPCHAR).append("build");
+        recursiveCreateDirectory(sourcedir.str());
+        recursiveCreateDirectory(builddir.str());
+
+        VStringBuffer hppFileNameBase("%sServiceBase.hpp", optService.get());
+        StringBuffer xsltpath(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPBASEHPP);
+        StringBuffer filefullpath;
+        filefullpath.append(sourcedir).append(PATHSEPCHAR).append(hppFileNameBase);
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppServiceBaseHpp);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppServiceBaseHpp, NULL, optFlags );
+            saveAsFile(sourcedir, hppFileNameBase, outputBuffer.str(), NULL);
+        }
+
+        VStringBuffer cppFileNameBase("%sServiceBase.cpp", optService.get());
+        outputBuffer.clear();
+        xsltpath.clear().append(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPBASECPP);
+        filefullpath.clear().append(sourcedir).append(PATHSEPCHAR).append(cppFileNameBase);
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppServiceBaseCpp);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppServiceBaseCpp, NULL, optFlags );
+            saveAsFile(sourcedir.str(), cppFileNameBase, outputBuffer.str(), NULL);
+        }
+
+        VStringBuffer srvHppFileNameBase("%sService.hpp", optService.get());
+        outputBuffer.clear();
+        xsltpath.clear().append(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPSRVHPP);
+        filefullpath.clear().append(sourcedir).append(PATHSEPCHAR).append(srvHppFileNameBase);
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppServiceHpp);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppServiceHpp, NULL, optFlags );
+            saveAsFile(sourcedir.str(), srvHppFileNameBase, outputBuffer.str(), NULL);
+        }
+
+        VStringBuffer srvCppFileNameBase("%sService.cpp", optService.get());
+        outputBuffer.clear();
+        xsltpath.clear().append(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPSRVCPP);
+        filefullpath.clear().append(sourcedir).append(PATHSEPCHAR).append(srvCppFileNameBase);
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppServiceCpp);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppServiceCpp, NULL, optFlags );
+            saveAsFile(sourcedir.str(), srvCppFileNameBase, outputBuffer.str(), NULL);
+        }
+
+        outputBuffer.clear();
+        xsltpath.clear().append(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPCMAKE);
+        filefullpath.clear().append(sourcedir).append(PATHSEPCHAR).append("CMakeLists.txt");
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppCMake);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppCMake, NULL, optFlags );
+            saveAsFile(sourcedir.str(), "CMakeLists.txt", outputBuffer.str(), NULL);
+        }
+
+        outputBuffer.clear();
+        xsltpath.clear().append(optXsltPath);
+        xsltpath.append(XSLT_ESDL2CPPTYPES);
+        filefullpath.clear().append(sourcedir).append(PATHSEPCHAR).append("primitivetypes.hpp");
+        if (checkFileExists(filefullpath.str()))
+            DBGLOG("ATTENTION: File %s already exists, won't generate again", filefullpath.str());
+        else
+        {
+            cmdHelper.defHelper->loadTransform( xsltpath, NULL, EsdlXslToCppTypes);
+            cmdHelper.defHelper->toMicroService( *structs, outputBuffer, EsdlXslToCppTypes, NULL, optFlags );
+            saveAsFile(sourcedir.str(), "primitivetypes.hpp", outputBuffer.str(), NULL);
+        }
+        return 0;
+    }
+
+    void printOptions()
+    {
+        puts("Options:");
+        puts("   --method <meth name>[;<meth name>]* Constrain to list of specific method(s)" );
+        puts("   --xslt <xslt file path>             Path to xslt files used to transform EsdlDef to c++ code" );
+        puts("   --preprocess-output <raw output directory> : Output pre-processed xml file to specified directory before applying XSLT transform" );
+        puts("   --show-inheritance                  Turns off the collapse feature. Collapsing optimizes the XML output to strip out structures" );
+        puts("                                       only used for inheritance, and collapses their elements into their child. That simplifies the" );
+        puts("                                       stylesheet. By default this option is on.");
+        puts(ESDLOPT_INCLUDE_PATH_USAGE);
+    }
+
+    virtual void usage()
+    {
+        puts("Usage:");
+
+        puts("esdl cpp sourcePath serviceName [options]\n" );
+        puts("\nsourcePath - Absolute path to the EXSDL Definition file ( XML generated from ECM )" );
+        puts("               which contains ESDL Service definition.\n" );
+        puts("serviceName  - Name of ESDL Service defined in the given EXSDL file.\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, 0, 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 c++ 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 optOutDirPath;
+    StringAttr optPreprocessOutputDir;
+    unsigned optFlags;
+
+protected:
+    StringBuffer outputBuffer;
+    Owned<IProperties> params;
+};
+
+
 //=========================================================================================
 //=========================================================================================
 
 
 IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
 IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
@@ -813,6 +1125,8 @@ IEsdlCommand *createCoreEsdlCommand(const char *cmdname)
         return new Esdl2EclCmd();
         return new Esdl2EclCmd();
     if (strieq(cmdname, "JAVA"))
     if (strieq(cmdname, "JAVA"))
        return new Esdl2JavaCmd();
        return new Esdl2JavaCmd();
+    if (strieq(cmdname, "CPP"))
+       return new Esdl2CppCmd();
     if (strieq(cmdname, "WSDL"))
     if (strieq(cmdname, "WSDL"))
         return new Esdl2WSDLCmd();
         return new Esdl2WSDLCmd();
     if (strieq(cmdname, "PUBLISH"))
     if (strieq(cmdname, "PUBLISH"))

+ 1 - 0
tools/esdlcmd/esdlcmd_shell.cpp

@@ -187,6 +187,7 @@ void EsdlCMDShell::usage()
            "   xsd               Generate XSD from ESDL definition.\n"
            "   xsd               Generate XSD from ESDL definition.\n"
            "   wsdl              Generate WSDL from ESDL definition.\n"
            "   wsdl              Generate WSDL from ESDL definition.\n"
            "   java              Generate Java code from ESDL definition.\n"
            "   java              Generate Java code from ESDL definition.\n"
+           "   cpp               Generate C++ code from ESDL definition.\n"
            "   publish           Publish ESDL Definition for ESP use.\n"
            "   publish           Publish ESDL Definition for ESP use.\n"
            "   list-definitions  List all ESDL definitions.\n"
            "   list-definitions  List all ESDL definitions.\n"
            "   get-definition    Get ESDL definition.\n"
            "   get-definition    Get ESDL definition.\n"