CCXML Voxeo 1.0 Development GuideHome  |  Frameset Home

  C: Events & Errors  |  TOC  |  CCXML Event Listing  
This documentation is for CCXML 1.0-Voxeo, which has been superceded by CCXML 1.0-W3C. The CCXML-Voxeo platform is not being updated any longer. The CCXML 1.0-W3C version, however, has many new features and is actively being enhanced. If you're writing a new CCXML application, you should use CCXML 1.0-W3C. Click here for the CCXML 1.0-W3C documentation.

Event Handling Basics

Perhaps the most important aspect of coding a solid CCXML application is proper event handling.  As such, we must familiarize ourselves with how CCXML event processing works and some proper error/event handling etiquette.

First off, to handle the large number of time-critical events in telephony applications CCXML events are always processed asynchronously.  The interpreter can accomplish asynchronous event handling by immediately removing every event from the event queue.  It then simply takes each event off to the side to process in its very own "space".  So in other words:  If we have 5 events enter the queue, each of the 5 events will be immediately removed from the queue and processed seemingly simultaneously.

Understanding the asynchronous nature of CCXML events we must always remember to take advantage of CCXML's state machine as to avoid 'error.statemismatch', 'error.outofsync'. and 'error.dialog.wrongstate' exceptions. 

If you are familiar with event and error handling in VoiceXML, then trapping CCXML events will seem pretty familiar to you.

In a VoiceXML application we would use the <catch> element:

              <catch event="EVENT">
                <!-- do something here -->
              </catch>


Whereas Call Control XML will catch and handle events via <transition>:

              <transition event="EVENT">
                <!-- do something here -->
              </transition>


Most events do carry a complex object containing various pieces of information ("fields") from or about the event. By using the 'name' attribute in our <transition>'s we can assign a "reference name" to this ECMAScript object allowing us to access the contained fields as such:


              <transition event="connection.CONNECTION_CONNECTED" name="evt">
                <log expr="'The callid is: [' + evt.callid + ']'"/>
                <var name="call_0" expr="evt.callid"/>
              </transition>


In this particular example, we accessed the field 'callid' from the event object that we named 'evt'.  As you can see, we can use the value(s) of an event object in any ECMAScript statement within the current <transition>.

Additionally, by using values stored in the event object we can effectively create stateless transitions, capable of handling events from multiple call legs or dialogs at any given moment.  Simply use if-then-else statements to determine the origin (i.e. which call leg, dialog, logical process, etc.) of said event.  Example:


              <transition event="connection.CONNECTION_DISCONNECTED" name="evt">
                <log expr="'The callid is: [' + evt.callid + ']'"/>
                <if cond="evt.callid == call_0">
                  <!-- do this -->
                <elseif cond="evt.callid == call_1"/>
                  <!-- do that -->
                <else/>
                  <!-- twiddle your thumbs -->
                </if>
              </transition>


Because of CCXML's native asynchronous event handling, and aggressive stance regarding session persistence, some safe-guards are absolutely necessary when coding your CCXML applications.  We must remember, there are no real fatal application errors in CCXML, so it is imperative that we have an appropriate <transition> handler present. To prevent 'runaway' applications always include in your CCXML documents an "all-encompassing" wildcard error handler, usually with an accompanying <exit> event, allowing you to catch any unexpected error events that have not be explicitly <transition>'ed.  Example:


              <transition event="error.*" name="evt">
                <log expr="'an error has occurred (' + evt.error + ')'"/>
                <exit/>
              </transition>


NOTE:  You must be extremely careful when trying to handle some sort of "clean-up" code as a result of this type of handler.  Reason being, if you are receiving this "unexpected" error type as a result of something that is happening in your "clean-up" code, you will create a nasty loop...  We recommend implementing an "error-count" situation to prevent this.  And if that error count is exceeded (a loop has been created), execute a completely different "clean-up" than normal that simply tells the application admins of the unexpected error, such as:


          <var name="unexpectedErrorCount" expr="0"/>

              <transition event="error.*" name="evt">
                <log expr="'an error has occurred (' + evt.error + ')'"/>
                  <if cond="unexpectedErrorCount == '0'">
                    <assign name="unexpectedErrorCount" expr="Number(unexpectedErrorCount) + 1"/>

                    <!-- RUN MY NORMAL CLEANUP CODE -->
                  <else/>
                    <assign name="unexpectedErrorType" expr="evt.error"/>
                    <send event="'http.get'" target="'myCoolErrorLog.asp'" namelist="unexpectedErrorType"/>
                    <!-- WE COULD ALWAYS TRANSITION THE EVENTS RELATED -->
                    <!-- TO THIS SEND AND EXIT WHEN CONFIRMED SUCCESS/FAILURE -->
                    <exit/>
                  </if>
              </transition>


Also note,  we need to make sure that if a conference is created, it needs to be "destroyed" before the app exits. Undestroyed conferences can potentially stay on the conference-mixer indefinitely.

It is also a good practice to, if possible, send a delayed "user.die" event.  You generally do not want an application that was intended to last about 90 seconds to be up for 30+ minutes.  You, as the application admin, simply need to decide what is the maximum time that you believe this app should be running before you consider it a rouge/zombie session.  Once you have made this decision, you can then set up an app-killer timing function, such as:


              <transition state="'init'" event="ccxml.loaded" name="evt">
                <!-- THIS WILL KILL THE APP IN 15 MIN -->
                <send event="'DIE_ZOMBIE_DIE'" target="session.id" delay="'900000'"/>
              </transition>

              <transition event="user.DIE_ZOMBIE_DIE">
                <exit/>
              </transition>





  ANNOTATIONS: EXISTING POSTS
jeross1
2/9/2007 12:30 PM (EST)
It took me a minute before I realized why I was getting an error asking for the </transition> tag on this code snippet.  The </exit> tag needs to be <exit/>.

<transition event="user.DIE_ZOMBIE_DIE">
  </exit> 
</transition>

-Judy
voxeojeff
2/9/2007 12:37 PM (EST)
Hi jeross1,

Nice catch!

We will make sure this is fixed asap. :-)

Best,

Jeff Menkel
Voxeo Corporation

login
  C: Events & Errors  |  TOC  |  CCXML Event Listing  

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