Browse Source

Merge pull request #11629 from afishbeck/crtConfigLocation

HPCC-20433 Allow both service and method level DESDL Request transforms

Reviewed-By: Rodrigo Pastrana <rodrigo.pastrana@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 years ago
parent
commit
67233ee44a

+ 101 - 35
esp/services/esdl_svc_engine/esdl_binding.cpp

@@ -161,7 +161,6 @@ void EsdlServiceImpl::init(const IPropertyTree *cfg,
     m_espServiceName.set(service);
     m_espProcName.set(process);
     m_bGenerateLocalTrxId = true;
-    m_custTrxCompileFail = false;
 
     VStringBuffer xpath("Software/EspProcess[@name=\"%s\"]", process);
     IPropertyTree * espcfg = cfg->queryPropTree(xpath);
@@ -299,6 +298,58 @@ void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entr
     }
 }
 
+void EsdlServiceImpl::addServiceLevelRequestTransform(IPropertyTree *customRequestTransform)
+{
+    if (!customRequestTransform)
+        return;
+
+    try
+    {
+        m_serviceLevelRequestTransform.setown(new CEsdlCustomTransform(*customRequestTransform));
+    }
+    catch(IException* e)
+    {
+        m_serviceLevelCrtFail = true;
+        StringBuffer msg;
+        e->errorMessage(msg);
+        ERRLOG("Service Level Custom Request Transform could not be processed!!: \n\t%s", msg.str());
+        e->Release();
+    }
+    catch (...)
+    {
+        m_serviceLevelCrtFail = true;
+        ERRLOG("Service Level Custom Request Transform could not be processed!!");
+    }
+}
+
+void EsdlServiceImpl::addMethodLevelRequestTransform(const char *method, IPropertyTree &methodCfg, IPropertyTree *customRequestTransform)
+{
+    if (!method || !*method || !customRequestTransform)
+        return;
+
+    try
+    {
+        Owned<CEsdlCustomTransform> crt = new CEsdlCustomTransform(*customRequestTransform);
+        m_customRequestTransformMap.setValue(method, crt.get());
+    }
+    catch(IException* e)
+    {
+        StringBuffer msg;
+        e->errorMessage(msg);
+        VStringBuffer errmsg("Custom Request Transform for method %s could not be processed!!: %s", method, msg.str());
+
+        m_methodCRTransformErrors.setValue(method, errmsg.str());
+        ERRLOG("%s", errmsg.str());
+        e->Release();
+    }
+    catch (...)
+    {
+        VStringBuffer errmsg("Custom Request Transform for method %s could not be processed!!", method);
+        m_methodCRTransformErrors.setValue(method, errmsg.str());
+        ERRLOG("%s", errmsg.str());
+    }
+}
+
 void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
 {
     VStringBuffer xpath("Definition[@esdlservice='%s']/Methods", service);
@@ -310,36 +361,20 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
         IPropertyTree * customRequestTransform = nullptr;
         try
         {
-            customRequestTransform = target_cfg->queryPropTree("Method/xsdl:CustomRequestTransforms");
+            customRequestTransform = target_cfg->queryPropTree("xsdl:CustomRequestTransform");
         }
         catch (IPTreeException *e)
         {
-            m_custTrxCompileFail = true;
             StringBuffer msg;
             e->errorMessage(msg);
-            ERRLOG("Encountered error while fetching \"hpcc:Transforms\" from service \"%s\" ESDL configuration. Ensure a single set of transforms is provided:\n%s ", service, msg.str());
-            e->Release();
-        }
+            VStringBuffer errmsg("Encountered error while fetching \"xsdl:CustomRequestTransform\" from service \"%s\" ESDL configuration: %s ", service, msg.str());
 
-        try
-        {
-            if (customRequestTransform)
-                m_customRequestTransform.setown(new CEsdlCustomTransform(customRequestTransform));
-            m_custTrxCompileFail = false;
-        }
-        catch(IException* e)
-        {
-            m_custTrxCompileFail = true;
-            StringBuffer msg;
-            e->errorMessage(msg);
-            ERRLOG("Custom Request Transform could not be processed, will be ignored!!: \n\t%s", msg.str());
+            m_serviceLevelCrtFail = true;
+            ERRLOG("%s", errmsg.str());
             e->Release();
         }
-        catch (...)
-        {
-            m_custTrxCompileFail = true;
-            ERRLOG("Custom Request Transform could not be processed, will be ignored!!");
-        }
+
+        addServiceLevelRequestTransform(customRequestTransform);
 
         m_pServiceMethodTargets.setown(createPTree(ipt_caseInsensitive));
         Owned<IPropertyTreeIterator> itns = target_cfg->getElements("Method");
@@ -358,14 +393,37 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
         Owned<IPropertyTreeIterator> iter = m_pServiceMethodTargets->getElements("Target");
         ForEach(*iter)
         {
-            const char *method = iter->query().queryProp("@name");
+            IPropertyTree &methodCfg = iter->query();
+            const char *method = methodCfg.queryProp("@name");
             if (!method || !*method)
                 throw MakeStringException(-1, "ESDL binding - found target method entry without name!");
-            const char *type = iter->query().queryProp("@querytype");
+
+            m_methodCRTransformErrors.remove(method);
+            m_customRequestTransformMap.remove(method);
+
+            IPropertyTree * customRequestTransform = nullptr;
+            try
+            {
+                customRequestTransform = methodCfg.queryPropTree("xsdl:CustomRequestTransform");
+            }
+            catch (IException *e)
+            {
+                StringBuffer msg;
+                e->errorMessage(msg);
+                VStringBuffer errmsg("Encountered error while fetching 'xsdl:CustomRequestTransform' from service '%s', method '%s' ESDL configuration: %s ", service, method, msg.str());
+
+                m_methodCRTransformErrors.setValue(method, errmsg.str());
+                ERRLOG("%s", errmsg.str());
+                e->Release();
+            }
+
+            addMethodLevelRequestTransform(method, methodCfg, customRequestTransform);
+
+            const char *type = methodCfg.queryProp("@querytype");
             if (type && strieq(type, "java"))
-                configureJavaMethod(method, iter->query(), classPath);
+                configureJavaMethod(method, methodCfg, classPath);
             else
-                configureUrlMethod(method, iter->query());
+                configureUrlMethod(method, methodCfg);
             DBGLOG("Method %s configured", method);
         }
     }
@@ -422,8 +480,14 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
     const char *mthName = mthdef.queryName();
     context.addTraceSummaryValue(LogMin, "method", mthName);
 
-    if (m_custTrxCompileFail)
-        throw MakeStringException(-1, "%s::%s disabled due to Custom Transform errors. Review tranform template in configuration.", srvdef.queryName(), mthName);
+
+    IEsdlCustomTransform *crt = m_customRequestTransformMap.getValue(mthdef.queryMethodName());
+    if (!crt)
+    {
+        if (m_serviceLevelCrtFail)
+            throw MakeStringException(-1, "%s::%s disabled due to Custom Transform errors. Review transform template in configuration.", srvdef.queryName(), mthName);
+        crt = m_serviceLevelRequestTransform;
+    }
 
     MapStringTo<SecAccessFlags>&  methaccessmap = const_cast<MapStringTo<SecAccessFlags>&>(mthdef.queryAccessMap());
     if (methaccessmap.ordinality() > 0)
@@ -505,6 +569,10 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
         if (!tgtcfg)
             throw makeWsException( ERR_ESDL_BINDING_BADREQUEST, WSERR_CLIENT, "ESDL", "Target not configured for method: %s", mthName );
 
+        StringAttr *crtErrorMessage = m_methodCRTransformErrors.getValue(mthName);
+        if (crtErrorMessage && !crtErrorMessage->isEmpty())
+            throw makeWsException( ERR_ESDL_BINDING_INTERNERR, WSERR_CLIENT, "ESDL", "%s", crtErrorMessage->str());
+
         implType = getEsdlMethodImplType(tgtcfg->queryProp("@querytype"));
 
         if (implType==EsdlMethodImplJava)
@@ -577,10 +645,10 @@ void EsdlServiceImpl::handleServiceRequest(IEspContext &context,
             reqcontent.set(reqWriter->str());
             context.addTraceSummaryTimeStamp(LogNormal, "serialized-xmlreq");
 
-            if (m_customRequestTransform)
+            if (crt)
             {
                 context.addTraceSummaryTimeStamp(LogNormal, "srt-custreqtrans");
-                m_customRequestTransform->processTransform(&context, reqcontent, m_oEspBindingCfg.get());
+                crt->processTransform(&context, reqcontent, m_oEspBindingCfg.get());
                 context.addTraceSummaryTimeStamp(LogNormal, "end-custreqtrans");
             }
 
@@ -1348,12 +1416,10 @@ void EsdlBindingImpl::addService(const char * name,
                 IEsdlDefService *srvdef = m_esdl->queryService(name);
                 if (!srvdef)
                 {
-                    DBGLOG("WARNING ESP Service %s has been re-assigned to ESDL service definition %s", name, loadedservicename.str());
+                    DBGLOG("ESP Service %s has been assigned to ESDL service definition %s", name, loadedservicename.str());
                     srvdef = m_esdl->queryService(loadedservicename.str());
-
-                    //Unfortunately this is being done in order to support mismatching ESP service name (the name given to this ESP Service in configuration)
-                    //and the ESDL service definition assigned to this service via DESDL configuration...
                     name = loadedservicename.str();
+
                     m_espServiceName.set(name);
                     m_pESDLService->m_espServiceType.set(name);
                     m_pESDLService->m_esdl.set(m_esdl);

+ 7 - 2
esp/services/esdl_svc_engine/esdl_binding.hpp

@@ -74,8 +74,9 @@ private:
     MapStringToMyClass<IException> javaExceptionMap;
     Owned<ILoggingManager> m_oLoggingManager;
     bool m_bGenerateLocalTrxId;
-    Owned<CEsdlCustomTransform> m_customRequestTransform;
-    bool m_custTrxCompileFail;
+    MapStringToMyClass<IEsdlCustomTransform> m_customRequestTransformMap;
+    Owned<CEsdlCustomTransform> m_serviceLevelRequestTransform;
+    bool m_serviceLevelCrtFail = false;
 
 #ifndef LINK_STATICALLY
     Owned<ILoadedDllEntry> javaPluginDll;
@@ -93,6 +94,7 @@ public:
     StringBuffer                m_serviceNameSpaceBase;
     StringAttr                  m_namespaceScheme;
     bool                        m_usesURLNameSpace;
+    MapStringTo<StringAttr, const char *> m_methodCRTransformErrors;
 
 public:
     IMPLEMENT_IINTERFACE;
@@ -145,6 +147,7 @@ public:
             m_pEsdlTransformer.clear();
         if(m_pServiceMethodTargets)
             m_pServiceMethodTargets.clear();
+        m_methodCRTransformErrors.kill();
     }
 
     virtual bool loadLogggingManager();
@@ -152,6 +155,8 @@ public:
     virtual void configureTargets(IPropertyTree *cfg, const char *service);
     void configureJavaMethod(const char *method, IPropertyTree &entry, const char *classPath);
     void configureUrlMethod(const char *method, IPropertyTree &entry);
+    void addServiceLevelRequestTransform(IPropertyTree *customRequestTransform);
+    void addMethodLevelRequestTransform(const char *method, IPropertyTree &methodCfg, IPropertyTree *customRequestTransform);
 
     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;

+ 10 - 17
esp/services/esdl_svc_engine/esdl_svc_custom.cpp

@@ -266,26 +266,19 @@ void CEsdlCustomTransformChoose::toDBGLog ()
 //
 // CEsdlCustomTransform methods
 //
-CEsdlCustomTransform::CEsdlCustomTransform(IPropertyTree *cfg)
+CEsdlCustomTransform::CEsdlCustomTransform(IPropertyTree &currentTransform)
 {
-    Owned<IPropertyTreeIterator> transformsIter = cfg->getElements("xsdl:CustomRequestTransform");
-    {
-        ForEach(*transformsIter)
-        {
-            IPropertyTree & currentTransform = transformsIter->query();
-            m_name.set(currentTransform.queryProp("@name"));
-            //if m_ruleName.length() == 0?
-            DBGLOG("Compiling custom ESDL Transform: '%s'", m_name.str());
+    m_name.set(currentTransform.queryProp("@name"));
+    DBGLOG("Compiling custom ESDL Transform: '%s'", m_name.str());
 
-            Owned<IPropertyTreeIterator> conditionalIterator = currentTransform.getElements("xsdl:choose");
-            ForEach(*conditionalIterator)
-            {
-                auto xslchooseelement = &conditionalIterator->query();
-                Owned<CEsdlCustomTransformChoose> currconditional = new CEsdlCustomTransformChoose(xslchooseelement);
-                m_customTransformClauses.append(*LINK(currconditional));
-            }
-        }
+    Owned<IPropertyTreeIterator> conditionalIterator = currentTransform.getElements("xsdl:choose");
+    ForEach(*conditionalIterator)
+    {
+        auto xslchooseelement = &conditionalIterator->query();
+        Owned<CEsdlCustomTransformChoose> currconditional = new CEsdlCustomTransformChoose(xslchooseelement);
+        m_customTransformClauses.append(*LINK(currconditional));
     }
+
 #if defined(_DEBUG)
     toDBGLog();
 #endif

+ 7 - 2
esp/services/esdl_svc_engine/esdl_svc_custom.hpp

@@ -125,7 +125,12 @@ private:
     void processChildClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext,  bool otherwise);
 };
 
-class CEsdlCustomTransform : public CInterface
+interface IEsdlCustomTransform : extends IInterface
+{
+       virtual void processTransform(IEspContext * context,  StringBuffer & request, IPropertyTree * bindingCfg)=0;
+};
+
+class CEsdlCustomTransform : implements IEsdlCustomTransform, public CInterface
 {
 private:
     CIArrayOf<CEsdlCustomTransformChoose> m_customTransformClauses;
@@ -134,7 +139,7 @@ private:
 public:
     IMPLEMENT_IINTERFACE;
     CEsdlCustomTransform(){}
-    CEsdlCustomTransform(IPropertyTree *cfg);
+    CEsdlCustomTransform(IPropertyTree &cfg);
 
 #if defined(_DEBUG)
     void toDBGLog()

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

@@ -1,5 +1,26 @@
  <Methods>
+       <xsdl:CustomRequestTransform>
+          <xsdl:choose>
+             <xsdl:when test="$clientversion=1.9">
+                <xsdl:SetValue target="Row/Name/First"  value="'service'" />
+             </xsdl:when>
+             <xsdl:otherwise>
+                <xsdl:SetValue target="Row/Name/Last" value="'zz'"/>
+             </xsdl:otherwise>
+          </xsdl:choose>
+       </xsdl:CustomRequestTransform>
     <Method name="JavaEchoPersonInfo" querytype="java" javamethod="EsdlExample.EsdlExampleService.JavaEchoPersonInfo"/>
-    <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>
+            <xsdl:choose>
+               <xsdl:when test="$clientversion=1.9">
+                  <xsdl:SetValue target="Row/Name/First"  value="'v1.9'"/>
+               </xsdl:when>
+               <xsdl:otherwise>
+                  <xsdl:SetValue target="Row/Name/Last" value="concat('v', $clientversion)"/>
+               </xsdl:otherwise>
+            </xsdl:choose>
+         </xsdl:CustomRequestTransform>
+   </Method>
 </Methods>