Cisco Support Community
cancel
Showing results for 
Search instead for 
Did you mean: 

[UCCX] Discovering Exceptions

UPDATES

December 29, 2016

The Editor and UCCX have changed since I originally wrote this document.  I'm not sure if it was a coincidence, or Cisco actually accepted my challenge, but I do know that they never contacted me about this document, or my thoughts on Exception handling.

At any rate, in newer versions of the Editor, and thus UCCX (the specifics are unknown to me, but from my testing v10.6(1)SU1 is a rough gauge), the Exceptions have been significantly reduced from 179 to just 18.  We've even gained the com.cisco.uccx.rest.client.RestClientException.  Which means that 160 Exceptions were removed.

Therefore, if you try to use my attached scripts on one of these newer systems, only 17 of the Exceptions actually exist.  In fact, if you try to run my script, it will fail.  You will get a validation error in the Editor if you do Tools > Validate, stating certain Exceptions are no longer available to you.  That list is:

com.cisco.archive.ArchiveAbortedIOException
com.cisco.archive.ArchiveException
com.cisco.archive.ArchiveFileNotFoundException
com.cisco.archive.ArchiveIOException
com.cisco.archive.ArchiveNotRecoveringException
com.cisco.archive.ArchiveObjectNotFoundException
com.cisco.archive.ArchivePermissionDeniedException
com.cisco.archive.ArchiveSystemIOException
com.cisco.archive.ArchiveUncaughtException
com.cisco.archive.ArchiveUnsupportedException
com.cisco.archive.ArchiveWizardException
com.cisco.archive.CompoundWizard$Exception
com.cisco.archive.EOAException
com.cisco.archive.impl.ArchiveFailureException
com.cisco.archive.impl.ArchiveOverridenException
com.cisco.database.aliasing.DBAliasingException
com.cisco.database.bar.DBBarException

So, I've modified the script to support the newer version, and have attached it to this document, along with the older script.  I have also updated the text within this document to reflect this change as well.

If you haven't immediately thought "What happens to my system after I upgrade it, and I was using one of the exceptions previously supported, but now no longer supported?"  Then I encourage you to go through all of your scripts, look at which exceptions you're referencing, and make sure they exist on v10.6+, else your scripts wont run.

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?

document_not_found.png

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 (or 18 if v10.6(1)SU1+) 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?

file_not_found.png

Weird.  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.FileException
com.cisco.file.FileExistException
com.cisco.file.FileNotFoundException *Already tried this one
com.cisco.file.InvalidFileClassException
com.cisco.file.NoAvailableSpaceException
com.cisco.file.impl.DbManagerException
com.cisco.file.impl.FileIOException
com.cisco.file.impl.FileMgrException
com.cisco.file.impl.FileRemoteException
com.cisco.file.impl.SyncFailedException

Ok, so, 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.

file_exist_exception.png

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?

wfexecution_exception.png

Note that the WFExecutionException will catch ANY and ALL exceptions within a script.

Wouldn't it be handy to be able to test all of the exception handlers in a matter of seconds, and have a nice looking report, showing which exceptions handlers caught 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 exceptions.
  3. The case script, which contains a recreation of your failing script steps, which the runner will run for each exception, in a matter of 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* for the 179 Exception version, and over 150 steps for the 18 Exception version, 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 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.

the_report.png

There are two major sections to the report:

  1. The exception thrown by the case in semi-plain english
  2. The list of all 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_exception.png

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

Versions with 179 Exceptions

the_results.png

Version with 18 Exceptions

uccx-exception-18.png

The report now clearly shows that, even though the original error message displayed: FileNotFoundException, it's the com.cisco.doc.Document Exception which we 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 in the 179 Exception versions, and DocumentException in the 18 Exception versions.

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 by calling into the Main script (which calls the runner+case script). You wouldn't even need to debug the script at this point.  Just call it and then your report will be uploaded.

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

Comments

Respect.

Hi,

for starters, here's the class diagram for (almost) all Exceptions.

cld2.png

G.

Gergely,

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?

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.

G.

It's good to see I'm not the only one who goes poking inside Cisco class files

@tanner.ezell share what you've got and you'll be greatly rewarded.

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.

G.

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.

exception-map-zoom.png

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

Hmm, indeed, it's not that obvious.

Anyway, I took out the ironing board again and sort of reorganised the diagram:

uccx-85-cld.png

And the XML, too.

G.

7364
Views
50
Helpful
9
Comments