CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  tutorial Advanced Event Handling  |  TOC  |  tutorial Your First Dialog  

Tutorial: Basic Error Handling

This Lesson will explore Voxeo's implementation of error handling, which is not adequately described by the W3C specification for CCXML; nevertheless, this tutorial builds on knowledge learned from tutorials one, two, and three. If you have not gone through those tutorials, now would be an outstanding time.

In this Lesson, we will:

Note: The code presented within this tutorial is intended for the "Prophecy - CCXML 1.0" application type only. Attempts to utilize this code on the "CCXML - Voxeo" application type will not function, as the latter platform is based on the W3C specification from 2002.  Prophecy CCXML 1.0 is compliant to the most recent specification from 2006.


Step 1: creating our initial CCXML structure

Since we have already worked our way up from the first few tutorials, we should know how we go about starting off a new CCXML document: We declare our initial xml declaration, and then our <ccxml> element containers, (remembering to specify the voxeo XML namespace, so that we can make use of the nifty extension elements!):


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">
</ccxml>


Step 2: wicked, wicked errors

As we are studying the concept of basic error handling, we will want to answer the incoming call first, right? Of course. There's plenty of time to break our ccxml application later on, after all. As we learned in our previous lessons, we will add an event handler for the "connection.alerting" event, and then <accept> the call:


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">
  <eventprocessor>
    <transition event="connection.alerting">
      <log expr="'*** connection.alerting ***'"/>
      <accept/>
      <log expr="'*** call accepted ***'"/>
    </transition>
  </eventprocessor>
</ccxml>


As we now know, the next asynchonous event that will be thrown during this action is that the app will answer the call, which moves us into the "connection.connected" event. But what happens when we try and <accept> a call that has already been accepted while in the "connection.alerting" phase? Huh? You don't know either? Well, let's find out:


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">
  <eventprocessor>

    <transition event="connection.alerting">
      <log expr="'*** connection.alerting ***'"/>
      <accept/>
      <log expr="'*** call accepted ***'"/>
    </transition>

    <transition event="connection.connected">   
      <log expr="'*** connection.connected ***'"/>
      <!-- hey, we cant accept a call twice! --> 
      <accept/>

    </transition>

  </eventprocessor>
</ccxml>


So what happens? This kind of haphazard tomfoolery leads to a new event type. The CCXML specification has defined all error events with the object prefix "error.". In this particular case, the event "error.connection.wrongstate" will be posted as a result of trying to invoke an action on a call which cannot be executed at that time. As always, this error is not immediately recognized -- it will be fired asynchronously. Now, what's interesting is this: Just like you would expect, we could catch this event with any of the following <transition> events:

<transition event="error*">
<transition event="error.connection.*">
<transition event="error.connection.wrongstate">

You seeing a trend here? I thought so. Seeing as  we are simply catching events based on the string name, we can drill down further and specify the various components for the "error" string to get finer-grained control over our error handling. For the purposes of our tutorial, (and to follow good coding practices), we will try and specify our <transition> as accurately, and as specific as possible. In addition, we can access all kinds of nifty information by accessing the fields of this event, (which is why we are specifying a "name" attribute for this <transition>. There are different fields defined for just about every kind of asynchonous event that we can trap, and the "error.wrongstate" event has a plethora of data that we can access. So what's the process for getting at all this useful data? It's pretty easy actually: All we do is add a variable assignment, or a <log> statement that references the following syntax:


[transition name].[field name]


Let's illustrate this a bit further by logging all these fields within our event handler, and seeing what they output:


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

  <eventprocessor>

    <transition event="connection.alerting">
      <log expr="'*** connection.alerting ***'"/>
      <accept/>
      <log expr="'*** call accepted ***'"/>
    </transition>

    <transition event="connection.connected">   
      <log expr="'*** connection.connected ***'"/>
      <!-- hey, we cant accept a call twice! --> 
      <accept/>
    </transition>

    <transition event="error.connection.wrongstate">
    <log expr="'***  event$.name = ' + event$.name"/>
      <log expr="'***  event$.connectionid = ' + event$.connectionid"/>
      <log expr="'***  event$.protocol = ' + event$.protocol"/>
      <log expr="'***  event$.reason = ' + event$.reason"/>
      <log expr="'***  event$.info = ' + event$.info"/>
      <log expr="'***  event$.connection = ' + event$.connection"/>
      <log expr="'***  event$.tagname = ' + event$.tagname"/>
      <log expr="'***  event$.eventid = ' + event$.eventid"/>
      <log expr="'***  event$.eventsource = ' + event$.eventsource"/>
      <log expr="'***  event$.eventsourcetype = ' + event$.eventsourcetype"/>
      <log expr="'***  event$.tagname = ' + event$.tagname"/>
      <exit/>

    </transition>
  </eventprocessor>
</ccxml>


As we detailed, you can see that we are catching the exect error that we are expecting. We also log out all the available fields that will be populated when this event is trapped, using the "[transition name].[field name]" syntax that we referenced above. As a reminder, we can't access these fields in an unnamed <transition>, folks. So what sort of data do we get from these fields? Let's take a peek at our log output when we place a call into the application:


log: *** event$.name = error.connection.wrongstate
log: *** event$.connectionid = 029e5f07ac0bc796a493d9f892d0b2ae
log: *** event$.protocol = sip
log: *** event$.reason = accept can only be executed in CONNSTATE_ALERTING
log: *** event$.info = undefined
log: *** event$.connection = [object Connection]
log: *** event$.tagname = accept
log: *** event$.eventid = f3c0e45d8c43c48b758561bfc4684416
log: *** event$.eventsource = 029e5f07ac0bc796a493d9f892d0b2ae
log: *** event$.eventsourcetype = ccxml
log: *** event$.tagname = accept


The bulk of these fields and the data that they return is detailed more thoroughly elsewhere in our CCXML documentation, but let's focus on the stuff that matters for this excercise: the "event$.reason" field tells us flat-out what we did wrong in  our CCXML coding efforts. Think of this field like your own tech support representative, as it will always tell you what's wrong with your application. It's kid sister field, "event$.tagname" tells us what CCXML element caused the problem in the first place. And of course Big Daddy "event$.name" tells us what we already know, (like most Dads seem to do), and relays to us the exact error event that we caught. Also note that we snuck in an addition that we didn't fully explain yet. Why is that? Well, we like being sneaky.  As a final error handling step, we are always, always, always going to <exit> the application after handling a fatal event. Otherwise, we could see that our CCXML session doesn't get shut down properly. Note: This is not good.


Step 3: making matters worse

From the above code examples and explanations, we know how we can properly trap and handle an error should one occur: we code a <transition> handler for the possible error types, and log some event fields to give us some diagnostic data, and then <exit> to prevent the possibility of a call not getting shut down properly. But what happens if we get an error within our error handler, smart guy?

All good coders recognize that we always write apps and try and account for not only expected errors, but more importantly, unexpected errors. This is why we will want to code in a catch-all error handler, so that in case something happens that we aren't planning on, we can still trap the error, and end the call gracefully, and not have mystified callers on one end, and a runaway CCXML session on the other end....that's bad news. From the above step, we realize that we can use the "error.*" wildcard event handler that will catch any CCXML errors that do not fall in the category of "error.connection.wrongstate". In order to illustrate this in action, let's write us some bad code that will break our neatly-designed application...I think that a reference to a non-existent object should do the trick quite nicely:


<?xml version="1.0" encoding="UTF-8"?>
<!-- NOTE THAT WE *MUST* DECLARE THE xmlns ATTRIBUTE -->
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

  <eventprocessor>

    <transition event="connection.alerting">
      <log expr="'*** connection.alerting ***'"/>
      <accept/>
      <log expr="'*** call accepted ***'"/>
    </transition>

    <transition event="connection.connected">   
      <log expr="'*** connection.connected ***'"/>
      <accept/>
    </transition>

    <transition event="error.connection.wrongstate">
      <log expr="'***  event$.name = ' + event$.name"/>
      <log expr="'***  event$.connectionid = ' + event$.connectionid"/>
      <log expr="'***  event$.protocol = ' + event$.protocol"/>
      <log expr="'***  event$.reason = ' + event$.reason"/>
      <log expr="'***  event$.info = ' + event$.info"/>
      <log expr="'***  event$.connection = ' + event$.connection"/>
      <log expr="'***  event$.tagname = ' + event$.tagname"/>
      <log expr="'***  event$.eventid = ' + event$.eventid"/>
      <log expr="'***  event$.eventsource = ' + event$.eventsource"/>
      <log expr="'***  event$.eventsourcetype = ' + event$.eventsourcetype"/>
      <log expr="'***  event$.tagname = ' + event$.tagname"/>
      <log expr="'** bogus object = ' + celebrities.that.keep.political.opinions.to.themselves"/>
      <exit/>
    </transition>
   
    <transition event="error.*">
      <log expr="'an error has occured (' + event$.name + ')'"/>
      <log expr="'*** ' + event$.name + ' detected  ***'"/>
      <log expr="'***  event$.name = ' + event$.name"/>
      <log expr="'***  event$.reason = ' + event$.reason"/>
      <log expr="'***  event$.tagname = ' + event$.tagname"/>
      <log expr="'***  event$.eventid = ' + event$.eventid"/>
      <log expr="'***  event$.eventsource = ' + event$.eventsource"/>
      <log expr="'***  event$.eventsourcetype = ' + event$.eventsourcetype"/>
      <voxeo:sendemail to="'youremailaddress@somewhere.com'"
                      from="'myApp@voxeo.com'"
                      type="'debug'"
                      body="'An unexpected error has occurred \n Time to panic! \n
                              Flee the cities, abandon all hope!'"/>

    <exit/>
    </transition>


  </eventprocessor>
</ccxml>



As we said above, we are going to log the value of an object which doesn't exist: "celebrities.that.keep.political.opinions.to.themselves" within the <transition> for our "wrongstate" handler. Since this object is undeclared, the CCXML interpreter won't know what this is, and will throw a fatal "error.semantic". You'll also note that we have added the "wildcard" event handler for the "error" wildcard string. Since we don't have an explicit handler for <transition event="error.semantic">, this event will be caught by our wildcard handler. You'll note that again, we are logging all the available fields in this new handler via the <log> element because, well, more information is better when we have to debug something, right? Astute readers will see the return of the <exit> tag within this handler, too, because, (feel free to read this part aloud), we always exit our CCXML explicitly when we encounter an error. But we did sneak in another addition, (remember: we are sneaky): The <voxeo:sendemail> extension element. What the heck is this all about? As we understand that not everyone watches a debugger stream 24x7 except Voxeo employees, we realize that the developer might want a more proactive means of being notified when an application bombs out on us. Enter the <voxeo:sendemail> element, which will send us an email that alerts us to this fact. Of course, you'll probably want to edit this so that, you know, your own email address is specified in order for this to work, and as it is an extension element, we must reference the voxeo XML namespace in our initial <ccxml> declaration, as we stated in Step 1.

Our code is now complete: We throw two separate errors within the CCXML application context, and handle them so cleanly that the caller will only hear sweet, sweet silence when dialing in to test this out. Of course, that's not really all that useful for real-world caller presentation, but we can handle this in our next lesson, where we cover advanced error handling for CCXML.


  Download the CCXML source code!

What we covered:



  ANNOTATIONS: EXISTING POSTS
0 posts - click the button below to add a note to this page

login
  tutorial Advanced Event Handling  |  TOC  |  tutorial Your First Dialog  

© 2008 Voxeo Corporation  |  Voxeo IVR  |  VoiceXML & CCXML IVR Developer Site