Clarity PPM

Expand all | Collapse all

Can I make an external SOAP call in a GEL script?

Jump to Best Answer
  • 1.  Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 08:30 AM

    We are trying to make a SOAP request to our Workday system within a GEL script in which we get time off requests and then run a resource XOG to update the resource calendar.

     

    The Workday request doesn't require authentication and we can make the request and get a response back in SoapUI without issue.

     

    However when making the request within a GEL script, it doesn't look like it's even making the connection at all as we are not getting a return code back and the raw XML result is coming back as [#document: null].

     

    Here is my gel script.  For now all we are trying to do is prove the connectivity to Workday and output the results in the log:

     

    I've modified the Workday endpoint to strip out the actual domain name .

     

     

    <gel:script xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:core="jelly:core"
    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"
    xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:sql="jelly:sql"
    xmlns:xog="http://www.niku.com/xog"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">


    <core:invokeStatic var="caConfigMngr" className="com.niku.union.config.ConfigurationManager" method="getInstance" />
    <core:set var="XogUrl" value="${caConfigMngr.getProperties().getWebServer().getSchedulerUrl()}/niku/xog" />
    <core:new className="com.niku.union.security.DefaultSecurityIdentifier" var="secId"/>
    <core:invokeStatic className="com.niku.union.security.UserSessionControllerFactory" method="getInstance" var="userSessionCtrl"/>
    <core:set value="${userSessionCtrl.init(username, secId)}" var="secId"/>
    <core:set value="${secId.getUserName()}" var="XOGUsername"/>
    <core:set value="${secId.getSessionId()}" var="sessionID"/>

    <gel:log category="Workday" level="INFO">Starting process</gel:log>

    <!-- Make call to Workday TIBCO Service -->

    <gel:parameter default="http://WORKDAY_URL:81/TIBCO_HS_DEV/Processes/Services/v2.1/WorkdayService.serviceagent/WorkdayPortEndpoint1" var="wkURL" />

    <soap:invoke endpoint="${wkURL}" var="wkResult">
    <soap:message>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://www.tibco.com/schemas/HumanSystems/SharedResources/XSD/v2.1/Schema.xsd12">
    <soapenv:Header/>
    <soapenv:Body>
    <sch:ClarityRequest>
    <sch:FromDt>2017-09-01</sch:FromDt>
    <sch:ToDt>2017-09-10</sch:ToDt>
    <sch:Channel_Id>Clarity</sch:Channel_Id>
    </sch:ClarityRequest>
    </soapenv:Body>
    </soapenv:Envelope>
    </soap:message>
    </soap:invoke>

    <gel:log category="Workday" level="INFO">Raw Result: ${wkResult}"</gel:log>
    <!-- Check to see if connection was successful -->

    <gel:set asString="true" select="$wkResult/SOAP-ENV:Envelope/SOAP-ENV:Body/ns0:ClarityResponse/ns0:Status/ns0:ReturnDescription/text()" var="wkCnResult"/>

    <core:choose>
    <core:when test="${wkCnResult == 'Successful'}">
    <gel:forEach select="$wkResult/SOAP-ENV:Envelope/SOAP-ENV:Body/ns0:ClarityResponse/ns0:GetTimeOffRequests" var="wkReqDetail">
    <gel:log category="Workday" level="INFO"><gel:expr select="$wkReqDetail/ns0:Logon/text()"/></gel:log>
    <gel:log category="Workday" level="INFO"><gel:expr select="$wkReqDetail/ns0:FirstName/text()"/></gel:log>
    <gel:log category="Workday" level="INFO"><gel:expr select="$wkReqDetail/ns0:LastName/text()"/></gel:log>
    <gel:log category="Workday" level="INFO"><gel:expr select="$wkReqDetail/ns0:TimeOffDt/text()"/></gel:log>
    <core:set value="$wkReqDetail/ns0:TimeOffHrs/text()" var="wkHrs"/>
    <core:if test="$wkHrs &gt; 4.01">
    <gel:log>Work day = false. Hours: ${wkHrs}</gel:log>
    </core:if>
    <core:if test="$wkHrs &lt; 4.01">
    <gel:log>Work day = true. Hours: ${wkHrs}</gel:log>
    </core:if>
    </gel:forEach>
    </core:when>
    <core:otherwise>
    <gel:log category="Workday" level="INFO">Connection to Workday was unsuccessful. Result Code: ${wkCnResult}</gel:log>

    </core:otherwise>
    </core:choose>

    </gel:script>



  • 2.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 12:19 PM

    My guess is that the Workday TIBCO Service needs you to specify a SOAPACTION.

     

    To check for the SOAPACTION.  Click on the Workday and look at the SOAPACTION value.

     

     

    V/r,

    Gene



  • 3.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 02:31 PM

    We applied SOAPAction and it still doesn’t work.  Running it from a .NET application or an Excel macro works fine.  I’m wondering if there is some proxy issue in Clarity that is preventing it from connecting.

     

    Rob Rubin

    BB&T, Assistant VP

    ADS Section Manager, Tools Team

    919.745.5848

    RRubin@BBandT.com



  • 4.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 02:46 PM

    To test the proxy, I would login to the server and open the endpoint url in a browser.  If there is a proxy, you should see something other that the endpoint XML.

     

    Make sure the browser any setup to auto proxy for you.

     

    Another option is to run this via a command line on the server and turn up the logging verbosity.

     

    V/r,

    Gene



  • 5.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 03:39 PM

    We created another simple process just to see if we could parse the WSDL:

     

    <gel:script xmlns:core="jelly:core"

    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"

    xmlns:x="jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary">

     

    <x:parse var="xmlSource" xml="http://wil-vtibdev03:12422/Processes/Services/v2.1/WorkdayService.serviceagent?wsdl" />

     

    <gel:log>${xmlSource.asXML()}</gel:log>

     

    </gel:script>

     

     

    And this does in fact return the WSDL XML code, so we know it can connect from a gel script.  Just not sure why the soap action returns nothing.

     

    Rob Rubin

    BB&T, Assistant VP

    ADS Section Manager, Tools Team

    919.745.5848

    RRubin@BBandT.com



  • 6.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-14-2017 07:42 PM

    So I coded up a simple WCF and it exhibits the same behavior.

     

    After a little poking about in the soap:invoke, for some reason, the response for the WCF is returned as a org.apache.xerces.dom.DeferredDocumentImpl.

     

    So to get the xml, instantiated a org.dom4j.io.DOMReader and read in the  org.apache.xerces.dom.DeferredDocumentImpl (org.w3c.dom.Document) into a org.dom4j.Document.

     

    With the then org.dom4j.Document I called the called asXML method to get a string of the response to validate I was getting something back from the WCF.

     

    My test gel:

     

    <gel:script xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:core="jelly:core"
    xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"
    xmlns:soap="jelly:com.niku.union.gel.SOAPTagLibrary"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:sql="jelly:sql"
    xmlns:x="jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary"
    xmlns:xog="http://www.niku.com/xog"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

         <gel:log category="Workday" level="INFO">Starting process</gel:log>

         <!-- Make call to Workday TIBCO Service -->

         <soap:invoke endpoint="http://localhost/TestWcf/Service1.svc?singleWsdl" var="xmlSource" soapAction="http://tempuri.org/IService1/GetData">
              <soap:message>
                   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://tempuri.org/">
                        <soapenv:Header/>
                        <soapenv:Body>
                             <GetData>
                                  <value>1</value>
                             </GetData>
                        </soapenv:Body>
                   </soapenv:Envelope>
              </soap:message>
         </soap:invoke>

         <core:new className="org.dom4j.io.DOMReader" var="domReader"/>
         <core:invoke on="${domReader}" method="read" var="dom4jDoc">
              <core:arg type="org.w3c.dom.Document"  value="${xmlSource}" />
         </core:invoke>
         
         <core:set var="xmlString" value="${dom4jDoc.asXML()}" />

         <core:set var="entries" value="${context.getVariables().entrySet().toArray()}" />
         <core:forEach var="entry" items="${entries}">
              <core:if test="${!entry.getKey().equalsIgnoreCase('systemScope')}" >
                   <gel:log> ${entry.getKey()} | ${entry.getValue()}</gel:log>
              </core:if>
         </core:forEach>

         <gel:log>${xmlString}</gel:log>
         <!-- Check to see if connection was successful -->

    </gel:script>

     

    Output:

     

     

    The last line is my xml response from my WCF from this class:

     

     

    Best I can tell is the org.apache.xerces.dom.DeferredDocumentImpl is an in-memory xml document and the gel:set tag needs it to be a real org.w3c.dom.Document.  I pushed it into a org.dom4j.Document for the asXML method.  On a side note the jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary uses dom4J.

     

    If you want to get it back into a  org.w3c.dom.Document take a look at the org.dom4j.io.DOMWriter.

     

    V/r,

    Gene



  • 7.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-15-2017 10:52 AM

    Well we are making progress.  Using org.dom4j.Document I am able to get the response XML back:

     

    Workday]Raw Result: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><ns0:ClarityResponse xmlns:ns0="http://www.tibco.com/schemas/HumanSystems/SharedResources/XSD/v2.1/Schema.xsd12"><ns0:Status><ns0:ReturnCode>000</ns0:ReturnCode><ns0:ReturnDescription>Successful</ns0:ReturnDescription></ns0:Status><ns0:GetTimeOffRequests><ns0:EmployeeId>781</ns0:EmployeeId><ns0:Logon>SS1005</ns0:Logon><ns0:FirstName>***</ns0:FirstName><ns0:LastName>***</ns0:LastName><ns0:Email>***</ns0:Email><ns0:TimeOffDt>2017-09-08</ns0:TimeOffDt><ns0:TimeOffHrs>4.0</ns0:TimeOffHrs></ns0:GetTimeOffRequests> ….

     

    However I cannot seem to parse the XPath to iterate through the xml and extract the actual values.

     

    For example, I want to get the ReturnDescription.

     

    If we have <core:set var="xmlResponse" value="${dom4jDoc.asXML()}" /> and I use:

     

    <gel:set select="$xmlResponse/SOAP-ENV:Envelope/SOAP-ENV:Body/ns0:ClarityResponse/ns0:Status/ns0:ReturnDescription/text()" var="wkCnResult"/>

     

    I get the error: <gel:set> Missing or invalid XML

     

    If I use <x:set select="$xmlResponse/SOAP-ENV:Envelope/SOAP-ENV:Body/ns0:ClarityResponse/ns0:Status/ns0:ReturnDescription/text()" var="wkCnResult"/> where x: is based on jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary , then I don’t get an error but the value of wkCnResult is blank/null.



  • 8.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-15-2017 01:07 PM

    Try parsing you xml string back into a org.w3c.dom.Document.

     

         <core:set var="xmlString" value="${dom4jDoc.asXML()}" />
         
         <core:new var="inputStreamReader" className="java.io.ByteArrayInputStream" >
              <core:arg value="${xmlString.getBytes()}" />
         </core:new>
         <gel:parse var="wkResult" file="${inputStreamReader}" />

         <gel:set asString="true" select="$wkResult/SOAP-ENV:Envelope/SOAP-ENV:Body/ns0:ClarityResponse/ns0:Status/ns0:ReturnDescription/text()" var="wkCnResult"/>

     

    V/r,

    Gene



  • 9.  Re: Can I make an external SOAP call in a GEL script?

    Posted 09-15-2017 01:19 PM

    That just returns   after it’s re-parsed.  I think I also have to remove the ns0 namespace as it’s not declared in the parent element.



  • 10.  Re: Can I make an external SOAP call in a GEL script?
    Best Answer

    Posted 09-15-2017 01:31 PM

    I have remove namespaces like this before:

     

    <gel:script
         xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary"
         xmlns:x="jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary"
         xmlns:aw="http://www.adventure-works.com"
         >

         <!-- jelly/gel has troubles with namespaces so let remove them -->
         <x:parse var="RemoveNameSpace">
              <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                   <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>
                   <xsl:template match="*">
                        <xsl:element name="{local-name()}">
                             <xsl:apply-templates select="@* | node()"/>
                        </xsl:element>
                   </xsl:template>
                   <xsl:template match="@*">
                        <xsl:attribute name="{local-name()}">
                             <xsl:value-of select="."/>
                        </xsl:attribute>
                   </xsl:template>
                   <xsl:template match="comment() | text() | processing-instruction()">
                        <xsl:copy/>
                   </xsl:template>
              </xsl:stylesheet>
         </x:parse>
         
              <!-- This is way our xml looks like without namespaces -->     
         <x:transform var="xmlData" xml= "${xmlRawData}" xslt="${RemoveNameSpace}" />
         <gel:log message="${xmlData.asXML()}" />

         <!-- Gel parses the document into a org.w3c.dom / appy transformation to remove namespaces-->
         <gel:parse var="gelXmlData">
              <x:transform xml= "${xmlRawData}" xslt="${RemoveNameSpace}" />
         </gel:parse>
         
    </gel:script>

     

    V/r,

    Gene