Browse Source

Merge pull request #11979 from afishbeck/desdlCRTBaseTarget

HPCC-21059 Enhance custom request transform targeting

Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 years ago
parent
commit
80e9f85cd0

+ 17 - 8
esp/services/esdl_svc_engine/esdl_binding.cpp

@@ -350,13 +350,22 @@ void EsdlServiceImpl::addMethodLevelRequestTransform(const char *method, IProper
     }
 }
 
-static void ensureMergeOrderedPTree(Owned<IPropertyTree> &target, IPropertyTree *src)
+static void ensureMergeOrderedEsdlTransform(Owned<IPropertyTree> &dest, IPropertyTree *src)
 {
     if (!src)
         return;
-    if (!target)
-        target.setown(createPTree(ipt_ordered));
-    mergePTree(target, src);
+    if (!dest)
+        dest.setown(createPTree(ipt_ordered));
+    //copy so we can make changes, like adding calculated targets
+    Owned<IPropertyTree> copy = createPTreeFromIPT(src, ipt_ordered);
+    const char *target = copy->queryProp("@target");
+    if (target && *target)
+    {
+        Owned<IPropertyTreeIterator> children = copy->getElements("*");
+        ForEach(*children)
+            children->query().setProp("@_crtTarget", target); //internal use only attribute
+    }
+    mergePTree(dest, copy);
 }
 
 void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
@@ -370,10 +379,10 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
         Owned<IPropertyTree> serviceCrt;
         try
         {
-            ensureMergeOrderedPTree(serviceCrt, target_cfg->queryPropTree("xsdl:CustomRequestTransform"));
+            ensureMergeOrderedEsdlTransform(serviceCrt, target_cfg->queryPropTree("xsdl:CustomRequestTransform"));
             Owned<IPropertyTreeIterator> transforms =  target_cfg->getElements("Transforms/xsdl:CustomRequestTransform");
             ForEach(*transforms)
-                ensureMergeOrderedPTree(serviceCrt, &transforms->query());
+                ensureMergeOrderedEsdlTransform(serviceCrt, &transforms->query());
         }
         catch (IPTreeException *e)
         {
@@ -416,10 +425,10 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
             Owned<IPropertyTree> methodCrt;
             try
             {
-                ensureMergeOrderedPTree(methodCrt, methodCfg.queryPropTree("xsdl:CustomRequestTransform"));
+                ensureMergeOrderedEsdlTransform(methodCrt, methodCfg.queryPropTree("xsdl:CustomRequestTransform"));
                 Owned<IPropertyTreeIterator> transforms =  methodCfg.getElements("Transforms/xsdl:CustomRequestTransform");
                 ForEach(*transforms)
-                    ensureMergeOrderedPTree(methodCrt, &transforms->query());
+                    ensureMergeOrderedEsdlTransform(methodCrt, &transforms->query());
             }
             catch (IException *e)
             {

+ 39 - 22
esp/services/esdl_svc_engine/esdl_svc_custom.cpp

@@ -26,7 +26,9 @@ CEsdlCustomTransformChoose::CEsdlCustomTransformChoose(IPropertyTree * choosewhe
 {
     if (choosewhen)
     {
-        IPropertyTree * whentree = choosewhen->queryPropTree("xsdl:when");
+        if (choosewhen->hasProp("@_crtTarget"))
+            crtTarget.set(choosewhen->queryProp("@_crtTarget"));
+        IPropertyTree * whentree = choosewhen->queryPropTree("xsdl:when"); //should support multiple when statements
         if (whentree)
         {
             StringBuffer testatt;
@@ -110,20 +112,20 @@ void CEsdlCustomTransformChoose::processClauses(IEspContext * context, IProperty
     }
 }
 
-void CEsdlCustomTransformChoose::processChildClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext,  bool otherwise)
+void CEsdlCustomTransformChoose::processChildClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext,  bool otherwise, IPropertyTree *origTree)
 {
     if (!otherwise)
     {
         ForEachItemIn(currNestedConditionalIndex, m_childChooseClauses)
         {
-            m_childChooseClauses.item(currNestedConditionalIndex).process(context, request, xpathContext);
+            m_childChooseClauses.item(currNestedConditionalIndex).process(context, request, xpathContext, origTree, nullptr);
         }
     }
     else
     {
         ForEachItemIn(currNestedConditionalIndex, m_childOtherwiseClauses)
         {
-            m_childOtherwiseClauses.item(currNestedConditionalIndex).process(context, request, xpathContext);
+            m_childOtherwiseClauses.item(currNestedConditionalIndex).process(context, request, xpathContext, origTree, nullptr);
         }
     }
 }
@@ -208,14 +210,36 @@ bool CEsdlCustomTransformChoose::evaluate(IXpathContext * xpathContext)
     return evalresp;
 }
 
-void CEsdlCustomTransformChoose::process(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext)
+void CEsdlCustomTransformChoose::process(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext, IPropertyTree *origTree, const char *defaultTarget)
 {
+    StringBuffer xpath;
+
+    if (crtTarget.length())
+        xpath.set(crtTarget.str());
+    else if (defaultTarget && *defaultTarget)
+        xpath.set(defaultTarget);
+
+    IPropertyTree *reqTarget = request;
+
+    if (xpath.length())
+    {
+        //we can use real xpath processing in the future, for now simple substitution is fine
+        xpath.replaceString("{$query}", xpathContext->getVariable("query"));
+        xpath.replaceString("{$method}", xpathContext->getVariable("method"));
+        xpath.replaceString("{$service}", xpathContext->getVariable("service"));
+        xpath.replaceString("{$request}", xpathContext->getVariable("request"));
+
+        reqTarget = origTree->queryPropTree(xpath.str());  //get pointer to the write-able area
+        if (!reqTarget)
+            throw MakeStringException(-1, "EsdlCustomTransformChoose::process error getting request target %s", xpath.str());
+    }
+
     bool result = false;
     try
     {
         bool result = evaluate(xpathContext);
-        processClauses(context, request, xpathContext, !result);
-        processChildClauses(context, request, xpathContext, !result);
+        processClauses(context, reqTarget, xpathContext, !result);
+        processChildClauses(context, reqTarget, xpathContext, !result, origTree);
     }
     catch (...)
     {
@@ -307,6 +331,7 @@ void CEsdlCustomTransform::processTransform(IEspContext * context, IPropertyTree
         xpathContext->addVariable("query", tgtcfg->queryProp("@queryname"));
         xpathContext->addVariable("method", mthdef.queryMethodName());
         xpathContext->addVariable("service", srvdef.queryName());
+        xpathContext->addVariable("request", mthdef.queryRequestType());
 
         auto user = context->queryUser();
         if (user)
@@ -363,24 +388,16 @@ void CEsdlCustomTransform::processTransform(IEspContext * context, IPropertyTree
         }
 
         Owned<IPropertyTree> theroot = createPTreeFromXMLString(request.str());
-        StringBuffer xpath = m_target.str();
-        if (!xpath.length())
-        {
+        StringBuffer defaultTarget;
             //This default gives us backward compatibility with only being able to write to the actual request
-            const char *tgtQueryName = tgtcfg->queryProp("@queryname");
-            xpath.setf("soap:Body/%s/%s", tgtQueryName ? tgtQueryName : mthdef.queryMethodName(), mthdef.queryRequestType());
-        }
-        //we can use real xpath processing in the future, for now simple substitution is fine
-        xpath.replaceString("{$query}", tgtcfg->queryProp("@queryname"));
-        xpath.replaceString("{$method}", mthdef.queryMethodName());
-        xpath.replaceString("{$service}", srvdef.queryName());
-        IPropertyTree *thereq = theroot->queryPropTree(xpath.str());  //get pointer to the write-able area
+        const char *tgtQueryName = tgtcfg->queryProp("@queryname");
+        defaultTarget.setf("soap:Body/%s/%s", tgtQueryName ? tgtQueryName : mthdef.queryMethodName(), mthdef.queryRequestType());
+
         ForEachItemIn(currConditionalIndex, m_customTransformClauses)
-        {
-            m_customTransformClauses.item(currConditionalIndex).process(context, thereq, xpathContext);
-        }
+            m_customTransformClauses.item(currConditionalIndex).process(context, theroot, xpathContext, theroot, defaultTarget);
+
         toXML(theroot, request.clear());
 
-        ESPLOG(LogMax,"MODIFIED REQUEST: %s", request.str());
+        ESPLOG(1,"MODIFIED REQUEST: %s", request.str());
     }
 }

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

@@ -99,6 +99,7 @@ private:
     CIArrayOf<CEsdlCustomTransformRule> m_otherwiseClauses;
     CIArrayOf<CEsdlCustomTransformChoose> m_childChooseClauses;
     CIArrayOf<CEsdlCustomTransformChoose> m_childOtherwiseClauses;
+    StringAttr crtTarget;
 
 public:
     IMPLEMENT_IINTERFACE;
@@ -110,7 +111,7 @@ public:
         DBGLOG("CEsdlCustomTransformClause released!");
 #endif
     }
-    void process(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext);
+    void process(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext, IPropertyTree *origTree, const char *defTarget);
 #if defined(_DEBUG)
     void toDBGLog();
 #endif
@@ -124,7 +125,7 @@ private:
     bool evaluate(IXpathContext * xpathContext);
     void processClauses(IPropertyTree *request, IXpathContext * xpathContext, CIArrayOf<CEsdlCustomTransformRule> & m_fieldTransforms);
     void processClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext, bool otherwise);
-    void processChildClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext,  bool otherwise);
+    void processChildClauses(IEspContext * context, IPropertyTree *request, IXpathContext * xpathContext,  bool otherwise, IPropertyTree *origTree);
 };
 
 interface IEsdlCustomTransform : extends IInterface