torsdag den 9. august 2018

Perform SOAP request with advanced headers in Informatica Powercenter Designer

My colleague had a problem in trying to access a SOAP web service. Specifically, he needed to provide extended SOAP headers in regards to the security requirements, a SAML assertion in this case, and the standard Informatica Web Transformation wasn't doing much for him.

We discovered that this is quite easy to accomplish by way of a Java Transformation instead. So here's how we did it.

In informatica, create the Java Transformation. Below illustration depicts it between two other transformations, and we can see how the input and output values are transferred between them.


Please pardon the use of the Danish language; I hope the gist of it will suffice.

Below picture further illustrates the input and output ports of the Java transformation. These exact names are immediately available to us from the Java code we write.


Now, let's add the Java-code specific to the task of calling a SOAP web-service with headers and all.

We have multiple tabs available on the transformation - I used only the 'On Input Row' and 'Import Packages'.

In 'Import Packages', specify the Java imports required to perform the task. For my use-case, these were sufficient:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;


Given these imports, we can go ahead and add the Java code in the 'On Input Row' tab. Please forgive the wall of text; I felt it was important to include the complete SOAP request, headers and body and all, for the sake of completeness.



try {
 logInfo("Sending soap request");

 String FagsystemNavn = fagsystemnavn_Input; // corresponds with the input variable name
 String KundeNummer = kundenummer_Input;  // corresponds with the input variable name
 String MeddelelseTypeNummer = meddelelsetypenummer_Input;  // corresponds with the input variable name
 String KanalTypeNummer = kanaltypenummer_Input; // 1=mail, 2=sms, 4=brev
 Integer currentTimeInSeconds = (int) (System.currentTimeMillis() / 1000);
 String MeddelelseBatchId = currentTimeInSeconds.toString();

 String soapTemplate = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns=\"http://task.dk/begrebsmodel/2009/01/15/\">\n"
   + "   <soapenv:Header>\n"
   + "      <wsse:Security soapenv:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n"
   + "         <Assertion AssertionID=\"d913c046fddbca7a55fca34caf18cafa\" IssueInstant=\"2007-05-14T11:45:21.835Z\" Issuer=\"test.unsigned\" MajorVersion=\"1\" MinorVersion=\"1\" xmlns=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\">\n"
   + "            <Conditions NotBefore=\"2007-05-14T11:43:21.834Z\" NotOnOrAfter=\"2112-05-14T11:43:21.834Z\"/>\n"
   + "            <AuthenticationStatement AuthenticationInstant=\"2007-05-14T11:45:21.834Z\" AuthenticationMethod=\"urn:oasis:names:tc:SAML:1.0:am:unspecified\">\n"
   + "               <Subject>\n"
   + "                  <NameIdentifier Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\" NameQualifier=\"task\">taskGuid=wEFI04,ou=task,ou=internal,ou=entities,dc=task,dc=dk</NameIdentifier>\n"
   + "                  <SubjectConfirmation>\n"
   + "                     <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod>\n"
   + "                  </SubjectConfirmation>\n" + "               </Subject>\n"
   + "            </AuthenticationStatement>\n" + "            <AttributeStatement>\n"
   + "               <Subject>\n"
   + "                  <NameIdentifier Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\" NameQualifier=\"task\">task=wEFI04,ou=task,ou=internal,ou=entities,dc=task,dc=dk</NameIdentifier>\n"
   + "                  <SubjectConfirmation>\n"
   + "                     <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod>\n"
   + "                  </SubjectConfirmation>\n" + "               </Subject>\n"
   + "               <Attribute AttributeName=\"Groups\" AttributeNamespace=\"urn:bea:security:saml:groups\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
   + "                  <AttributeValue>PRIMARY_IDENTITY_Guid=14a2d120-bbda-4b62-aa27-1bbd8751f47f,ou=task,ou=internal,ou=entities,dc=fd,dc=dk</AttributeValue>\n"
   + "                  <AttributeValue>AUTH_LEVEL_6</AttributeValue>\n"
   + "                  <AttributeValue>EFfdfdfdbehandlerPRG</AttributeValue>\n"
   + "               </Attribute>\n" + "            </AttributeStatement>\n"
   + "         </Assertion>\n" + "      </wsse:Security>\n" + "   </soapenv:Header>\n"
   + "   <soapenv:Body>\n" + "      <ns:MeddelelseMultiSend_I>\n" + "         <ns:Kontekst>\n"
   + "            <tsk:HovedOplysninger xmlns:tsk=\"http://foobar.dk/begrebsmodel/xml/schemas/kontekst/2007/05/31/\">\n"
   + "               <tsk:TransaktionsID>A12345678ZZ</tsk:TransaktionsID>\n"
   + "               <tsk:TransaktionsTid>2010-10-14T13:30:47</tsk:TransaktionsTid>\n"
   + "            </tsk:HovedOplysninger>\n" + "         </ns:Kontekst>\n"
   + "         <ns:FagsystemNavn>${FagsystemNavn}</ns:FagsystemNavn>\n"
   + "         <ns:MeddelelseBatchID>${MeddelelseBatchId}</ns:MeddelelseBatchID>\n"
   + "         <ns:Meddelelser>\n" + "            <ns:Meddelelse>\n"
   + "               <ns:MeddelelseTypeNummer>${MeddelelseTypeNummer}</ns:MeddelelseTypeNummer>\n"
   + "               <ns:MeddelelseAfsenderReference>99</ns:MeddelelseAfsenderReference>\n"
   + "               <ns:KundeNummer>${KundeNummer}</ns:KundeNummer>\n"
   + "               <ns:MeddelelseOprettetAfMedarbejder>a5441</ns:MeddelelseOprettetAfMedarbejder>\n"
   + "               <ns:KanalTypeNummer>${KanalTypeNummer}</ns:KanalTypeNummer>\n"
   + "   <ns:KanalAdresseStruktur>\n" + "    <ns:AdresseValg>\n"
   + "     <ns:EmailAdresseStruktur>\n" + "      <ns:EmailAdresse>\n"
   + "       <ns:EmailAdresseEmail>anon@foobar.dk</ns:EmailAdresseEmail>\n"
   + "      </ns:EmailAdresse>\n" + "     </ns:EmailAdresseStruktur>\n"
   + "<!--\n" + "     <ns:TelefonNummerStruktur>\n"
   + "      <ns:TelefonNummerStruktur>\n"
   + "       <ns:TelefonNummer>888878787</ns:TelefonNummer>\n"
   + "      </ns:TelefonNummerStruktur>\n"
   + "     </ns:TelefonNummerStruktur>\n" + "-->\n" + "    </ns:AdresseValg>\n"
   + "   </ns:KanalAdresseStruktur>\n"
   + "               <ns:Filer/>\n" + "            </ns:Meddelelse>\n" + "         </ns:Meddelelser>\n"
   + "      </ns:MeddelelseMultiSend_I>\n" + "   </soapenv:Body>\n" + "</soapenv:Envelope>";

 String soapMessage = soapTemplate.replace("${FagsystemNavn}", FagsystemNavn)
   .replace("${MeddelelseBatchId}", MeddelelseBatchId)
   .replace("${MeddelelseTypeNummer}", MeddelelseTypeNummer).replace("${KundeNummer}", KundeNummer)
   .replace("${KanalTypeNummer}", KanalTypeNummer);

 URL url = new URL("http://the-url-to-your-soap-service");
 HttpURLConnection connection = (HttpURLConnection) url.openConnection();

 connection.setDoOutput(true);
 connection.setDoInput(true);
 connection.setRequestMethod("POST");
 connection.setRequestProperty("Content-Type", "text/xml");
 connection.setReadTimeout(5000);
 OutputStream out = connection.getOutputStream();
 Writer wout = new OutputStreamWriter(out);

 wout.write(soapMessage);
 wout.close();
 InputStreamReader isr = null;
 if (connection.getResponseCode() <= 400) {
  isr = new InputStreamReader(connection.getInputStream());
 } else {
  isr = new InputStreamReader(connection.getErrorStream());
 }

 BufferedReader in = new BufferedReader(isr);
 StringBuffer responseSoapMessage = new StringBuffer();
 String inputLine = in.readLine();

 while (inputLine != null) {

  // the response xml contains both the merged xml and the deploy logs.
  responseSoapMessage.append(inputLine);
  inputLine = in.readLine();
 }
 in.close();
 System.out.println("responseSoapMessage" + responseSoapMessage.toString());
 int webServiceKaldSucces_Output;
 
 if (responseSoapMessage.toString().contains(
   "<n1:AdvisNummer>1001</n1:AdvisNummer><n1:AdvisTekst>Request with 1 messages was acknowledged</n1:AdvisTekst>")) {
  webServiceKaldSucces_Output = 1; // succes in web-service call - stored in the output variable
  logInfo("Soap request - succes");
 } else {
  webServiceKaldSucces_Output = 0; // error in web-service call  - stored in the output variable
  logInfo("Soap request - error");
 }

 generateRow(); // Required by Informatica to generate output.
 
} 
catch (Exception ex) 
{
 logError(ex.getMessage());
}


The above code pieces a SOAP-request together, replacing specific values within it with the input-port values. Then, by way of a standard Java HttpURLConnection, it fires off the request, and reads the response into a StringBuilder object. For our use-case we report succes or failure by looking for a particular piece of String-value, we had no need to parse the response further.

Do note the call to 'generateRow()', this is required by Informatica to populate the output value(s).

Also note the calls to logInfo(message) and logError(message), respectively, these enable logging into the Informatica Session log. So by all means go crazy with them, you can never have enough logging.


Hope it helps!


Buy me a coffeeBuy me a coffee

Ingen kommentarer:

Send en kommentar