SOAP Driver: Process response on publisher channel

Hi,

I had previously built a SOAP driver to retrieve data on heartbeats on the publisher channel (ITP), but I would like to have it make the request from the subscriber channel, to allow me to use triggers to control when to get data and what to get.
I have kept all the policies (other than ITP) on the publisher channel, because the correct thing to do is still have the incoming data go through the publisher channel, right? Unfortunately, for me, it is not quite so simple to get the events through the publisher channel.

Please let me know if I am going about this all wrong and if there is another way to achieve what I am trying to do. My mind is tainted by how it was done previously:)

My attempt starts with a static SOAP request in the OTP like this that matches triggers:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="query cmd dncv" version="1.0" xmlns:cmd="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsCommandProcessor" xmlns:dncv="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.DNConverter" xmlns:es="http://www.novell.com/nxsl/ecmascript" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:query="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsQueryProcessor" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cal="http://www.novell.com/nxsl/java/java.util.GregorianCalendar">
	<xsl:param name="srcQueryProcessor"/>
	<xsl:param name="destQueryProcessor"/>
	<xsl:param name="srcCommandProcessor"/>
	<xsl:param name="destCommandProcessor"/>
	<xsl:param name="dnConverter"/>
	<xsl:param name="fromNds"/>
	<xsl:variable name="i" select="0"/>
	<xsl:template match="node()|@*">
		<xsl:copy>
			<xsl:apply-templates select="@*|node()"/>
		</xsl:copy>
	</xsl:template>
	<xsl:template match="trigger" xmlns:java="java:dk.unic.infotjeneste.webservice.returTyper" xmlns:m="https://infotjeneste.uni-c.dk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
		<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:oio:sd:snitflader:2011.12.01" xmlns:ns="http://rep.oio.dk/cpr.dk/xml/schemas/core/2005/03/18/" xmlns:ns1="http://rep.oio.dk/sd.dk/xml.schema/20080201/" xmlns:ns2="http://rep.oio.dk/sd.dk/xml.schema/20070301/" xmlns:ns3="http://rep.oio.dk/sd.dk/xml.schema/20070401/">
			<soapenv:Header/>
			<soapenv:Body>
				<urn:GetEmployment>
					<urn:InstitutionIdentifier>AA</urn:InstitutionIdentifier>
					<urn:EmploymentIdentifier>123456</urn:EmploymentIdentifier>
					<urn:ActivationDate>2024-06-07</urn:ActivationDate>
					<urn:DeactivationDate>2024-07-07</urn:DeactivationDate>
					<ns2:ActivationTime>00:00:00</ns2:ActivationTime>
					<ns2:DeactivationTime>23:59:59</ns2:DeactivationTime>
					<ns3:DepartmentIndicator>true</ns3:DepartmentIndicator>
					<ns3:EmploymentStatusIndicator>true</ns3:EmploymentStatusIndicator>
					<ns3:ProfessionIndicator>true</ns3:ProfessionIndicator>
					<ns3:SalaryAgreementIndicator>true</ns3:SalaryAgreementIndicator>
					<ns3:SalaryCodeGroupIndicator>true</ns3:SalaryCodeGroupIndicator>
					<ns3:WorkingTimeIndicator>true</ns3:WorkingTimeIndicator>
					<urn:UUIDIndicator>true</urn:UUIDIndicator>
				</urn:GetEmployment>
			</soapenv:Body>
		</soapenv:Envelope>
		<operation-data url="~drv.data.sd.GetEmploymentChanged-URL~" instID="AA" regID="9K"/>
	</xsl:template>
</xsl:stylesheet>


What I would expect to happen is that this request is sent via the subscriber channel to the application and I receive a response, which goes through into the ITP. In the ITP I would be able to transform the response to an ADD event, which should go through to the publisher channel policies. That, however, is not the case - it never reaches the publisher channel.

The response I receive looks similar to this:

<nds dtdversion="2.0">
  <source>
    <product build="20190731_0848" instance="SOAP-SDEmpChangedAtDate01" version="4.1.0.0">Identity Manager Driver for SOAP</product>
    <contact>NetIQ Corporation</contact>
  </source>
  <output>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/200
1/XMLSchema-instance">
      <soapenv:Body>
        <sd:GetEmploymentChangedAtDate20111201 creationDateTime="2024-07-19T10:44:49" xmlns:cpr20050318="http://rep.oio.dk/cpr.dk/xml/schemas/core/2005/03/18
/" xmlns:sd="urn:oio:sd:snitflader:2011.12.01" xmlns:sd20070301="http://rep.oio.dk/sd.dk/xml.schema/20070301/" xmlns:sd20070401="http://rep.oio.dk/sd.dk/xml.
schema/20070401/" xmlns:sd20080201="http://rep.oio.dk/sd.dk/xml.schema/20080201/" xsi:schemaLocation="urn:oio:sd:snitflader:2011.12.01 https://service.sd.dk/
sdws/xml/schema/sd.dk/xml.schema/20111201/GetEmploymentChangedAtDate/SD_GetEmploymentChangedAtDateInterface_20111201.xsd">
          <sd:RequestStructure>
            <sd:InstitutionIdentifier>AA</sd:InstitutionIdentifier>
            <sd:EmploymentIdentifier>123456</sd:EmploymentIdentifier>
            <sd20070301:ActivationDate>2024-06-07</sd20070301:ActivationDate>
            <sd20070301:ActivationTime>00:00:00</sd20070301:ActivationTime>
            <sd20070301:DeactivationDate>2024-07-07</sd20070301:DeactivationDate>
            <sd20070301:DeactivationTime>23:59:59</sd20070301:DeactivationTime>
            <sd20070401:DepartmentIndicator>true</sd20070401:DepartmentIndicator>
            <sd20070401:EmploymentStatusIndicator>true</sd20070401:EmploymentStatusIndicator>
            <sd20070401:ProfessionIndicator>true</sd20070401:ProfessionIndicator>
            <sd20070401:SalaryAgreementIndicator>true</sd20070401:SalaryAgreementIndicator>
            <sd20070401:SalaryCodeGroupIndicator>true</sd20070401:SalaryCodeGroupIndicator>
            <sd20070401:WorkingTimeIndicator>true</sd20070401:WorkingTimeIndicator>
            <sd:UUIDIndicator>true</sd:UUIDIndicator>
            <sd20070401:FutureInformationIndicator>false</sd20070401:FutureInformationIndicator>
          </sd:RequestStructure>
          <sd:Person>
            <cpr20050318:PersonCivilRegistrationIdentifier>1234567890</cpr20050318:PersonCivilRegistrationIdentifier>
            <sd:Employment>
              <sd:EmploymentIdentifier>123456</sd:EmploymentIdentifier>
              <sd:Profession changedAtDate="2024-06-18">
                <sd20070301:ActivationDate>2024-01-01</sd20070301:ActivationDate>
                <sd20070301:DeactivationDate>9999-12-31</sd20070301:DeactivationDate>
                <sd:JobPositionIdentifier>1010</sd:JobPositionIdentifier>
                <sd:EmploymentName>Biolog</sd:EmploymentName>
                <sd20070401:AppointmentCode>0</sd20070401:AppointmentCode>
              </sd:Profession>
            </sd:Employment>
          </sd:Person>
        </sd:GetEmploymentChangedAtDate20111201>
      </soapenv:Body>
    </soapenv:Envelope>
  </output>
  <operation-data instID="AA" regID="9K" url="https://service.sd.dk/sdws/services/GetEmploymentChangedAtDate20111201" xmlns:cal="http://www.novell.com/nxsl/j
ava/java.util.GregorianCalendar" xmlns:java="java:dk.unic.infotjeneste.webservice.returTyper" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:m="https
://infotjeneste.uni-c.dk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</nds>

I transform the response into an ADD event in the exact same form as I did, when the SOAP request was made from the ITP itself. The transformed event looks like this:

<nds dtdversion="2.0">
  <source>
    <product build="20190731_0848" instance="SOAP-SDEmpChangedAtDate01" version="4.1.0.0">Identity Manager Driver for SOAP</product>
    <contact>NetIQ Corporation</contact>
  </source>
  <output>
    <add class-name="Group" xmlns:cal="http://www.novell.com/nxsl/java/java.util.GregorianCalendar" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:uuid="http://www.novell.com/nxsl/java/java.util.UUID" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <association>AA123456</association>
      <add-attr attr-name="CN">
        <value>04DBF9A557AF49018219E936B86ACD36</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageID">
        <value>123456</value>
      </add-attr>
      <add-attr attr-name="XATTRIB-CPR">
        <value>1234567890</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageInstitutionID">
        <value>AA</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageRegionID">
        <value>9K</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWagePendingChangeDate">
        <value>2024-01-01</value>
      </add-attr>
    </add>
  </output>
  <operation-data instID="AA" regID="9K" url="https://service.sd.dk/sdws/services/GetEmploymentChangedAtDate20111201" xmlns:cal="http://www.novell.com/nxsl/java/java.util.GregorianCalendar" xmlns:java="java:dk.unic.infotjeneste.webservice.returTyper" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:m="https://infotjeneste.uni-c.dk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</nds>

What I note here is that opposed to when the SOAP request was made from the ITP, the event becomes wrapped in a <output> tag rather than an <input> tag.
When this document exits the ITP, the trace shows:

[07/19/24 11:16:43.288]:SOAP-SDEmpChangedAtDate ST:
<nds dtdversion="2.0">
  <source>
    <product build="20190731_0848" instance="SOAP-SDEmpChangedAtDate01" version="4.1.0.0">Identity Manager Driver for SOAP</product>
    <contact>NetIQ Corporation</contact>
  </source>
  <output>
    <add class-name="Group" xmlns:cal="http://www.novell.com/nxsl/java/java.util.GregorianCalendar" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:uuid="http://www.novell.com/nxsl/java/java.util.UUID" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <association>AA123456</association>
      <add-attr attr-name="CN">
        <value>35BB35178405446DA8AA0B02BD3B492B</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageID">
        <value>123456</value>
      </add-attr>
      <add-attr attr-name="XATTRIB-CPR">
        <value>1234567890</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageInstitutionID">
        <value>AA</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWageRegionID">
        <value>9K</value>
      </add-attr>
      <add-attr attr-name="XATTRIBWagePendingChangeDate">
        <value>2024-01-01</value>
      </add-attr>
    </add>
  </output>
  <operation-data instID="AA" regID="9K" url="https://service.sd.dk/sdws/services/GetEmploymentChangedAtDate20111201" xmlns:cal="http://www.novell.com/nxsl/java/java.util.GregorianCalendar" xmlns:java="java:dk.unic.infotjeneste.webservice.returTyper" xmlns:js="http://www.novell.com/nxsl/ecmascript" xmlns:m="https://infotjeneste.uni-c.dk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</nds>
[07/19/24 11:16:43.289]:SOAP-SDEmpChangedAtDate ST:No schema mapping policies.
[07/19/24 11:16:43.289]:SOAP-SDEmpChangedAtDate ST:Resolving association references.
[07/19/24 11:16:43.289]:SOAP-SDEmpChangedAtDate ST:Processing returned document.
[07/19/24 11:16:43.289]:SOAP-SDEmpChangedAtDate ST:Processing operation <add> for .
[07/19/24 11:16:43.289]:SOAP-SDEmpChangedAtDate ST:End transaction.

Specifially the line "Processing operation <add> for ." is confusing to me. I have found that when I set a dest-dn on the event it would be included in this line i.e. "Processing operation <add> for data\dataitems\35BB35178405446DA8AA0B02BD3B492B. For an ADD event I wouldn't have a dest-dn, which means this can't be required.
Still, it would do nothing further.

I am assuming that it is because the event is returned to the subscriber channel, on which there are no more policies.
How do I get the information through the publisher channel policies?

Thanks in advance for anyone who attempted to comprehend this

  • 0  

    Hej,

    You can do what you want to do, but it would add needless complexity to the driver - issuing a query from the subscriber and then on the ITP create an object in the vault, could be done simpler.

    I have multiple drivers which does similar things, and what I do is, in my trigger job I do a query to the application, I then use the query result to update the Vault and then veto the job.

    Like:

    if trigger and name = '...'
        result = query(...)
        if result
            CRUD operation

    In your OTP you will tmatch the query and issue a soap query, on the ITP you will process the soap query result (create instance nodes) which you then can process.

    That makes it simpler and easier to maintain.

  • 0  

    I think you have correctly identified the problem.  If the SOAP service from outside made a call to your endpoint listener, it would have sent it in as an <input> document.

    But you sent a query/command from the Sub channel, <input> which returns as a response, <output>.

    What you need to do is catch this case and convert it.  If you simply appended an <add> to the current node, you would still be inside the output.

    I have solved this before in a very complex driver, but icannot remember the very specific steps needed...

    I THINK you can append XML element input to .. and then veto the event.  Next policy object can then process it.  (Has to be the next policy object.  This oject won't let you see the change properly.

  • 0  

    Another option: if you can query for a singular object

    What I have done at one driver (although REST) is I trigger a job on all objects that should exist on the connected application, that trigger is then transformed into a sync, because I have all the attributes of the object in the filter set to publisher sync and subscriber reset, driver queries for application values and resets them to application values via its integrated filter processes.

  • 0 in reply to   

    Thanks for the reply.

    I already tried to replace the <output> with <input> in a second policy on ITP. I am not sure if that is exactly the same as appending <input> as xml as you are suggesting. Either way, that lead to the driver complaining that an <output> tag was missing in the response. I tried adding an empty <output> tag and while it didn't complain it also did nothing still.

  • 0 in reply to   

    Thanks for the reply.

    If i understand you correctly, I would receive the response on the subscriber channel where I made the query from. That would be fine if I didn't have a significant amount of publisher channel logic that I was hoping not to rewrite.

    Perhaps the needless complexity is needed in this case:) What would that entail?

  • 0 in reply to   

    Thanks for the reply.

    Unfortunately I cannot query for a singular object. The query varies and can return multiple objects. 

  • 0   in reply to 

    Well actually you can but it is hard to go into specifics.

    Basically when you do a query for a specific object transfer that query in itp policy set into normal query for multiple objects and save the attributes that would make this query for singular object into operation property, then on otp policy set filter out response to only objects that fit that saved operation property.

    So in general you can scope query down with driver policies if schim or application do not support query for singular object.

  • 0  

    Hi,

    from what I understand is that your issue is to use job-triggers to execute queries instead of facilitating the heartbeat event, right?

    Do you need to have these queries to be executed at that exact moment when the job-trigger event occurred?

    What I have used in the past is a driver-scoped variable to hold the 'trigger'.

    On driver startup initialize a driver-scoped variable for example 'gTrigger' with a specific value 'false'.

    On the subscriber channel in an event transformation policy compose a rule which acts on the job-trigger and sets the value of the variable gTrigger to 'true'.

    On the publisher channel in an event transformation policy create a rule which acts on the driver heartbeat and checks the value of the driver scoped variable 'gTrigger'.

    If the value is 'true' then you execute your queries and you set the value of the variable gTrigger to 'false'.

    The advantage is that you can re-use your code from a previous driver. The disadvantage is that your query is not executed at the exact job-trigger moment.

    Btw. you can use this variable to hold additional information like query parameters.

    Hope this helps