Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.
Showing results for
Search instead for
Did you mean:
UCCX 8.x - a Really Simple SOAP Client (no custom JAR)
Problem: it's a common task for a call center routing script to communicate with a remote procedure using the SOAP protocol, over HTTP. Usually, the script sends a piece of information to the SOAP server, parses the response, reads some useful data and then continues.
Analysis: Unfortunately, there is no built in step or method to create a simple SOAP client within a CRS script (and I don't blame the UCCX programmers for that). Some people use various frameworks (JAX-WS, Axis) to make SOAP calls easier, this usually requires an IDE like NetBeans or Eclipse, building a Java package, and uploading it - along with the framework itself - as custom JARs to the UCCX server. Personally, I don't really like that idea:
it makes debugging complicated;
if any change is needed, one must rebuild the whole solution, upload it to the UCCX server, restart the CCX engine - who likes this hassle;
I don't see the reason why we can't keep things simple and stupid - meaning, CRS scripts can do Java, and Java (at least Java 6 which comes with UCCX 8.x) can do everything you need to build a Really Simple SOAP Client.
UPDATE 1: if you are interested in a more OOP-style WS client (created with JAX-WS) read the following post:
UPDATE 2: I got a couple of comments and private messages about the CCX editor not accepting the second Set step due to one line:
return new String(baos.toByteArray());
This is a bug in some versions of UCCX. Unfortunately, for some reason it will sort of "hide" the Set step if it contains the above line. I don't know why it won't allow calling the toByteArray() method on a ByteArrayOutputStream object, this method is legal. Some versions of UCCX may accept it, some just won't. For instance, UCCX 8.0.2 happily accepts that method, UCCX 7.0SR5 does not.
If your UCCX is affected by the bug, then try replacing the above line with the following:
This has been tested and found working with UCCX Premium 7.0SR5 which does contain the bug, so the Set step disapperared with the original line but it did not with the replacement.
SOAP Request: sending this XML document to the SOAP server. This is usually HTTP POSTing it to the web server;
read the SOAP response (this is an XML document, too);
parse the SOAP response and filter out the information we are looking for.
Looking at the tools the CCX editor offers for the above four tasks:
1. creating an XML document - easy. Two alternatives:
XML Template: you can upload an XML document on to the UCCX server, with some tokens; then, using the Keyword Transform Document step (where the already existing XML document will be the template), just replace the tokens with the desired values. That works just great if you don't want anything complicated and you are absolutely sure the result will also be a valid XML document (so there is no chance the Keyword Transform Document messes it up with some unexpected characters etc).
You can, of course, use Java to build the XML from scratch if you want to have more control. Personally, I like this option.
2. sending this XML document - now, one may say, there's the Create URL Document step, and it can do HTTP Post. Well, that's right, the step exists, it can sort of POST, but it's not the POST we are looking for. This step actually formats the value to be sent differently (application/x-www-form-urlencoded) which may or may not be accepted by the SOAP server. Java gives you more precise tools for that.
3. reading the SOAP response - this actually goes along with the previous step. But if we send something unacceptable to the SOAP server, we cannot expect a valid response either. Using Java gives you more granulated control.
4. parse the SOAP response and "fish out" the desired piece of information - easy. The Get XML Document Data step can operate with XPath expressions perfectly. So no Java code is needed.
**** DISCLAIMER: This is a proof of concept. I am not responsible for any damage, including the death of your favorite pet/rockstar. I cannot guarrantee this solution is the best, I cannot even guarrantee it would work in your system. Tested with IP IVR version 8.0(2) ****
I am going to explain the whole process using an example. Again, y u no build any packages, custom JARs. I don't even expect you to be fluent in Java.
In our not at all imaginary call center, there's a UCCX script that is supposed to do some routing decision based on a number which is calculated by some legacy systems, which speak SOAP only.
As we can see, it's just a plain ordinary XML document (sans the XML declaration, for the sake of brevity). The so-called root element is soapenv:Envelope (its namespace in red, first row - expected by the SOAP server). The first child node is soapenv:Header; notice, it is empty - my SOAP server does not expect any headers. Then the soapenv:Body - this contains the next element, mis:GetCallAggregates (with the namespace URI in red, again), and this contains two elements, startDate and endDate (each containing a date and time string).
In other words, I am asking the SOAP server to run the GetCallAggregates method, with two parameters, startDate (its value is 2012-04-01T00:00:00) and endDate (its value is 2012-04-02T23:59:59). Actually, I am asking for some statistical information (CallAggregates) within the specified dates (1st April 2012 00:00:00, and 2nd April 2012 23:59:59).
This can be very easily constructed in Java, using only the tools Java 6 offers. And, as we know, Java 6 - more precisely, JDK 1.6 - is included in UCCX and if you have IP IVR or UCCX Enhanced or Premium, you can use it, most likely with Set steps.
Constructing XML in Java
First, I am going to create a new variable, type String, and name it soapRequest (initial value: null).
Then I am going to insert a Set step into my script, that would yield the value of the above soapRequest variable. The value field would be a closure (a block of Java code. Don't panic, I'll explain that, too!)
The source code I am using at this step (please note: // starts a line of comment):
// first, create a new buffer:
java.io.StringWriter buffer = new java.io.StringWriter();
// define namespace URI's and prefixes
// (take a look at the SOAP request XML above, you'll see there are two namespace prefix - URI pairs
Just some more details on them: soapResponseString is the raw "string", sent by the SOAP server as response. Since the Get XML Document Data step can only operate on documents of which type is Document, we'll have to use a different variable, with the expected type, soapResponseDoc. And, as you might have guessed, the soapServiceEndpoint contains the URL of the SOAP Server endpoint.
Then, the Set step. The variable is the soapResponseString, and the value field contains another nice block of code again:
Source code (again, don't panic!):
// create a ByteArrayOutputStream - this is actually a buffer
// we are going to use to store the response coming from the SOAP server
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
// this is quite unnecessary: assigning the value of the soapRequest (still holding our XML document)
// to another variable, named content, type String; but anyway, it's just cleaner
String content = soapRequest;
// specify a timeout - 5000 milliseconds - if the web server does not start sending back
// anything within this timeframe, an exception will be raised
int readTimeout = 5000;
// now, the following methods are enclosed by a try..catch block
// to catch any exceptions - we just want to have control over them
// remember, an uncaught exception might stop your CRS script execution
// and you might not want that
// a new URL, which is the soapServiceEndpoint variable value (http://ip:port/ etc):
java.net.URL url = new java.net.URL(soapServiceEndpoint);
// again, if an error occurs, let's just send the stack trace to stdout (stdout.log)
// and then return null
} // try..catch block ends here
// construct a new String, and return that to the CRS script:
return new String(baos.toByteArray());
} // closure ends here
(N.B.: If your UCCX is affected by a strange bug - see UPDATE 2 - try replacing
return new String(baos.toByteArray());
There's still one more step, cast this soapResponseString to a Document. Notice the next step, the Get XML Document Data step expects the document be created by the Create XML Document step. But that's not a problem:
Voilá, we've got our SOAP response document. Again, it's something like this if everything goes perfectly:
<faultstring>Unmarshalling Error: unexpected element (uri:"", local:"boo"). Expected elements are (none)</faultstring>
Getting the desired value from the SOAP response XML document
For now, let's pretend everything went fine, there were no errors. I am interested in the value of the "value" element of the first CallAggregate element (where the date is 2012-04-01 and the "parameterName" is AbandonIn30):
We use the Get XML Document Data step for it (the result variable is named inString, type String, inital value: null):
The actual XPath expression:
Of course, you might check whether there are any soap:Fault nodes, you can do that using the XPath expression //faultcode (for instance).
Check Wikipedia or w3schools for more XPath examples.
Conclusion: this is a simplistic approach, yet it works very well in a real environment.