09-07-2012 08:26 AM - edited 10-04-2018 09:19 PM
October 4, 2018
I tested the 10.6(1) version of this tool in 11.6(1) and it still works.
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.
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 (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?
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.
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?
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.
There are three scripts at work here:
Let's take a look at these three scripts in more details.
The main script is comprised of only two parts:
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 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 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 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:
Let's take a look at a report generated from our original FileNotFound exception above.
Versions with 179 Exceptions
Version with 18 Exceptions
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.
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.
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
Respect.
Hi,
for starters, here's the class diagram for (almost) all Exceptions.
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.
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:
And the XML, too.
G.
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: