[UCCX] Discovering Exceptions


Sep 7, 2012 8:26 AM
Sep 7th, 2012

The Problem

If you were to reference a Document in the repository, which doesn't actually exist in the repository, what would happen to your script?


Without proper exception handling in your script, this would halt the execution of your script, and then proceed to play the "System Problems" message provided by the default script of the application.

I hear you asking, "Anthony, what can I do about this?"

Well, you can use the On Exception Goto step, which will catch the exception when it happens, preventing your script from halting.

The next challenge is navigating the 179 exceptions provided to you within the On Exception Goto step, to pick just the right one for the job. So, which one do you pick? If you look back at your error message, you see the FileNotFoundException being mentioned, so why not start with that?


That didn't work. Let's look back at the section where we found our FileNotFoundException, to see if there is something else we can try.



com.cisco.file.FileNotFoundException *Already tried this one








Wow, that's quite a few to choose from; however, it looks like the FileExistException might be a good second choice, let's try that and see if it works.


Ok, so at this point, we could keep on guessing exceptions to use, and work our way through the list, eventually finding an exception to handle our exception. But, is the exception that you found really the best one for the job, or did you just settle on the first one that worked, due to frustration?


Editors Note: The WFExecutionException will catch any and all exceptions within a script. Use carefully.

Wouldn't it be handy to be able to test all 179 exception handlers in less than 5 seconds, and have a pretty report of which exceptions where thrown by your failing script step?

Now, you can! I have created a system that works on all licensing models of UCCX, which can catch and report on your failing script steps.

The Solution

There are three scripts at work here:

  1. The main script, which runs the exception runner and then uploads the report to the repository.
  2. The runner script, which runs through the exception handling workflow for all 179 exceptions.
  3. The case script, which contains a recreation of your failing script steps, which the runner will run 179 times in less than 5 seconds.

Let's take a look at these three scripts in more details.

The Main Script

The main script is comprised of only two parts:

  1. A subflow for calling the runner. This is done to bypass the slowness that is active debugging. If we were to active debug the runner, with its over 2,000 steps of execution*, it would take a really long time for it to complete. And if you were to connect to the UCCX engine over a VPN, it will take even longer!
  2. Uploading the report to the repository with your authenticated user account's credentials.

To begin the process, you would have this script open in your editor, and simply begin the active debug process (F5 on your keyboard).

Once the main script finishes execution, your report will be uploaded in the repository and ready for your review. Navigate to the default language folder, and click the document icon to the left of the filename. This should open the report right in your browser.** We'll cover the report in a later section.

The Runner Script

The runner script is comprised of many moving parts. To summarize what it's doing: it uses the WFExecutionException handler as a safety net, as it attempts to catch the exception produced in the case script, with each of the 179 exceptions available to you. Any further understanding of this script will be left as an exercise to the reader.

The Case Script

The case script should contain as few steps as possible to reproduce the failure you are experiencing in your production (or lab) script. For example, if I were facing a DocumentNotFound exception, I would not want to put in my IVR's greeting and menus. I would just slim down the testing to the document steps pertaining to the failure. Sometimes, that also means creating variables in this script; and feel free to do so. In fact, you could even create multiple case scripts, each with its own test case, and then repoint the subflow within the runner script, to pick which one you will run next.

Because you will not be using any exception handling within this script, the exception will flow upwards to the runner script for proper handling. Therefore, don't place any exception handling in here, or you will actually prevent the system from working as intended.

The Report

The report that is uploaded to the repository is an HTML document. You will need to view it in a web browser, and can do so by simply clicking on the icon to the left of the filename.


There are two major sections to the report:

  1. The exception thrown by the case in semi-plain english
  2. The list of 179 exception handlers, and a TRUE or FALSE value indicating whether or not the exception handler could handle the exception

Let's take a look at a report generated from our original FileNotFound exception above.

  • The Exception Thrown - Here you get an opportunity to read the error message thrown by your failing script step


  • The Results - Here you can quickly identify which exception handlers caught your exception.


...output omitted...


The report now clearly shows us that none of the file exception handlers worked, even though the original error message displayed, clearly states: FileNotFoundException. It is the document exception handlers which we truly needed.

The Conclusion

In conclusion, with this system in place, it would have taken me no time at all to figure out that the best exception handler to use would be: DocumentNotFoundException.

I hear you asking, "But Anthony, what if my testing requires a phone call, or an HTTP trigger?"

Simply modify the case script to include steps such as: Accept, Play Prompt, Send HTTP Response, etc. Then create an Application/Trigger for you to kick off the process. You wouldn't even need to debug the script at this point.

The Challenge

I challenge the community to take this system and improve upon it. I am a firm believer in collaboration, and that together we could make a better solution, than any one of us individually.

I also challenge Cisco to improve the exception handling facility within UCCX to be easier to use and more robust. As examples for Cisco: I would like to see more consistent error messages, and to be able to handle the ContactInactiveException on a per Contact basis.

*Because the runner executes over 2,000 steps, you will need to increase your Max Number of Executed Steps from 1,000 to 3,000 at a minimum. This requires you to restart the UCCX Engine, so plan for it a small outage to make this change.

**My testing shows that Firefox works best

Average Rating: 5 (8 ratings)


Anthony Holloway Mon, 09/10/2012 - 17:08 (reply to Gergely Szabo)


How did you...Where did you...Wow!  This is awesome.

It even shows me that I was incorrect on my statement that the WFExecutionException handles all exceptions.  Apparently that title belongs to the ApplicationException.

I just ran some additional tests, and it appears as though I was looking at your map incorrectly.  At first glance, it looks like all exception lead to the ApplicationException, where in fact, the AE points to the left towards the WFEE, which I am already using.  Now, that exception is obviously the not the top dog in your map, but it does not appear that there is a one-for-one association with the blocks in your map, and what you can choose from the list in the editor.  For now, I will keep the WFEE as the safety net.

This is so cool.  Thank you for posting this, and thank you double if you made it!  I must know where it came from, or how you made it.

I'll update my post to correct a few things, including the scripts I have attached.

Any info on why the DocumentNotFound error actually displays as FileNotFound?

Gergely Szabo Mon, 10/01/2012 - 22:08 (reply to Anthony Holloway)

Hi, I actually noticed that you had written ApplicationException "covers" all exceptions - actually, as you realised later, it does not, at least not all of the exceptions. I sort of felt too shy to start barking about this, thinking that the diagram was (more or less) clear enough ;-)

Anyway, congratulations for winning the Doc Award.


Anthony Holloway Tue, 10/02/2012 - 07:11 (reply to Gergely Szabo)

With how the ApplicationException box sits in the middle/top section of the map, plus all of the incoming arrows, it made it seem to me like it was at the top of the heirachy.  But I see now, that the single outgoing arrow from the ApplicationException box, is in fact to the WFEE box.


Next time don't be so shy!  Your map is still cool in my book.  Thanks for the kind words.

Gergely Szabo Tue, 09/11/2012 - 00:06 (reply to Anthony Holloway)

Hi Anthony.

Actually, it's not that difficult. Even though the  documentation is er... not so brilliant, the internals of UCCX are  relatively easy to read; classes - including various Exceptions - are  named and organised logically.

Before I start explaining how I got that class  hierarchy map, the answer to your question "why the DocumentNotFound  error actually displays as FileNotFound" is quite simple. The step that  threw this exception, actually had caught a java.io.FileNotFound  exception, which was then rethrown as  com.cisco.doc.DocumentNotFoundException - so you can catch that in your script. Simple, you may say, let's just reverse engineer all  the steps and see what's being caught and rethrown - well, this is  exactly what I thought when I had started this project, loooong time  before your post was born, but later I discovered it would require way  too much effort, so I gave it up. Why: behind the scenes, actually, a  lot much is going on. For instance, in this particular case, the  DocumentManager is being asked to resolve the file, and actually its  resolve method throws that java.io.FileNotFoundException. Well, how I  got to something named "DocumentManager" from the "Get XML Document Data  step", you might ask. This is the most difficult (and interesting) part  of it: reading call hierarchy.

The Get XML Document Data step is actually a Java Bean (as we know, all steps are Java Beans), which is of course a Java class: com.cisco.wf.steps.io.GetXMLDocValueStep. Its execute(WFWorkflowTask) method (let's just skip the question why I picked this method) does this:

org.w3c.dom.Document xmlDocument = ((DomDocument)doc).getDom();

This is actually a call to com.cisco.wf.steps.io.XMLDocument.getDom(). Which, in turn, calls

com.cisco.wf.steps.io.XMLDocument.getXMLDom(), which is, again, quite simple: it just calls a static method,

com.cisco.wf.steps.io.XMLDocument.convertDocToDom(). Now, it's getting a bit bumpy, but anyway, the relevant part of this last method is a call to an other method, com.cisco.doc.AbstractLocalizableDocument.getInputStream(). This calls com.cisco.doc.AbstractLocalizableDocument.resolve0(ApplicationContext, Locale) (again, let's just skip the fact this is already "imaginary", the class  being abstract), and we already arrived at the top of the call  hierarchy,

com.cisco.doc.NameDocument.resolve0(ApplicationContext), which in turn is actually implemented as

com.cisco.doc.impl.DocumentManagerImpl.resolve(NameDocument, ApplicationContext).  If you take a look at this method, it actually contains the message  that is shown with the exception: "user document '/path/to/file'" -  interestingly, the rest of the text (starting "nested exception")  already comes from WFException (which is extended by WFRuntimeException which is extended by WFExecutionException which is extended by DocumentException which is extended by DocumentIOException which is extended by DocumentNotFoundException in our case, and this DocumentNotFoundException was thrown right after the java.io.FileNotFoundException had been caught in the

com.cisco.wf.steps.io.GetXMLDocValueStep.execute(WFWorkflowTask) method (read: Get XML Doc Value step's bean's execute method).

It took around two hours to figure this out after I  read your post. Long time. You see, there was a reason I abandoned this  whole thing. But I still wanted to create a class hierarchy map, so I it  can be helpful when trying to figure out manually what your script does  automatically. ;-) This is how I did that:

Took the UCCX 8.5 installation CD. A lots of RPM's.  Uncompressed the interesting ones (following the naming convention).  Looked for jar files. Uncompressed interesting ones. Wrote a bash script  to filter out the classes named *Exception.

Created a project in Eclipse. Included all the jar files mentioned above, so ObjectAid's Class Diagram can resolve the hierarchy.  One by one, I started adding the *Exception classes. Almost puked seeing  the automatically generated result. Did some reorganization so lines  don't overlap. The result is in the PNG file above. If you happen to  have Eclipse, try to install Class Diagram and then you can view or  modify the UML diagram itself instead of the image. The source of the  diagram file is here: https://dl.dropbox.com/u/1020679/cld2.ucls

Are you still interested? ;-)

I have several ideas, like

1. a map of "what throws why" - list of all the relevant exceptions a step may throw;

2. a map of "this is thrown by what" - like the above, but from  the opposite direction, a list of exceptions and with corresponding  steps;

3. write a short explanation to all of the exceptions, even though I think they are named logically.

What's your current opinion on this.



Login or Register to take actions

This Document

Posted September 7, 2012 at 8:26 AM
Comments:9 Avg. Rating:5
Views:4566 Contributors:3
Categories: Express

Related Content