4.1. Example: JSP parcel tracking application

Dynamic dialogs are often generated based on an input provided by the user. Consider the example of an automated phone-based parcel tracking system. This system would ask the user for his or her tracking number, then look up the status of that parcel in a database.

Assume that a parcel company has already implemented an enterprise information system where information about each parcel's whereabouts is sent to some central computing facility as the parcel passes through each transfer point: at pick-up, when it arrives at a processing center, when it leaves the processing center, when it arrives at the airport to be shipped to another processing center, etc. Assume further that there is an enormous enterprise infrastructure in place which makes sure that each one of these status events is inserted into some enormous relational database at corporate headquarters.

Imagine the parcel company wants to give their customers phone access to the status of their parcels. We are charged with the responsibility of deploying a customer-facing telephone system where customers can call in and find out the whereabouts of any package in the central database, given that package's tracking number. As this is our first foray into integrating voice into an enterprise information system, let's start with a basic proof-of-concept pilot project that achieves the following goals:

  • provides a simple voice-based interface to the parcel information database,

  • operates on its own telephone number (i.e. does not need to include call center integration work, call control, etc. -incidentally, this is an ideal candidate for remote hosting),

  • can be written and deployed quickly.

Based on these requirements, a logical solution would be to use a dynamic server page technology, such as JSP, to query that relational database and produce a VoiceXML response. We would then need to either (a) purchase some VoiceXML portal hardware, hook the telephony hardware end of it to an 800 number and the TCP/IP end of it to the server hosting our JSP pages, or (b) use an outsourced VoiceXML service and point that service to our JSP server - either over the public internet or over leased lines, depending on our anticipated traffic. The deployment architecture for either option is shown in Figure 4-1. The portion shown in the dashed box can be deployed either on-site or at a VoiceXML-enabled remote-hosted call center, depending on business requirements.

Figure 4-1. Physical deployment for the package information telephone system


Let's consider the voice user interface (VUI) for this system. As this is just a pilot, we can keep it very simple: collect a tracking number, query the database, render the results using text-to-speech, then ask if the user wants to track another package. Add a welcome and goodbye message and some minimal error handling, and you have the call flow shown in Figure 4-2.

Figure 4-2. Call flow diagram for package-tracking application


We assume each of the components shown in Figure 4-1 is in place and operating correctly. Our remaining task is to write the actual VoiceXML application. This application could be structured into two separate VoiceXML documents:

Tracking Number Collector

This is a static document that collects the tracking number and validates its format, then posts it up to the Tracking Info Reporter document.

Tracking Info Reporter

This is a dynamically generated dialog that looks up all events pertaining to the given tracking number and structures them in the form of a VoiceXML dialog. This document can also contain a form field to ask if the caller wants to track another parcel.

The Tracking Number Collector is implemented as a static VoiceXML document, since the contents of this document do not depend on the database state. The Tracking Info Reporter is implemented as a JSP page that uses JDBC to access the package information database.

The Tracking Number Collector document is relatively straightforward: it is simply a VoiceXML document broken into two forms:

  • welcome simply plays the welcome message and then goes on to the CollectTrackingNo form;

  • CollectTrackingNo collects the tracking number from the user and submits the form results to the Tracking Info Reporter page for evaluation using a submit element.

The VoiceXML code for this document is shown in Example 4-1.

Example 4-1. The Tracking Number Collector
<?xml version="1.0" encoding="iso-8859-1"?>
<vxml version="2.0">
  <form id="welcome">
    <block>
      <prompt>
        Welcome to the telephone package tracking system.
      </prompt>
      <goto next="#CollectTrackingNo"/>
    </block>
  </form>

  <form id="CollectTrackingNo">
    <field name="trackingNo" type="digits">
      <prompt>
        Please tell me the 10 digit tracking number of your package.
      </prompt>
    </field>

    <filled>
      <prompt>
        Please wait while I'm checking this package's status.
      </prompt>
      <submit next="TrackingInfoReporter.jsp" 
              namelist="trackingNo"/>
    </filled>
  </form>
</vxml>

This document simply collects the tracking number with the trackingNo field and then submits it to TrackingInfoReporter.jsp using submit. Recall that submit causes the VoiceXML interpreter to request the URI specified with the next attribute using an HTTP POST. The contents of the POST are the variables specified in the submit element's namelist attribute. These can be accessed as name/value pairs from any dynamic server page.

The TrackingInfoReporter.jsp file embodies most of the application logic. It begins with JSP import directives that allow us to instantiate JDBC and Java Collection objects from within our JSP page.

<%@ page import="java.util.*" %>
<%@ page import="java.sql.*" %>

This is followed by the beginning of the actual VoiceXML page delivered to the voice-portal hardware. This preamble contains the document type definition reference and the opening vxml and form tags for the resulting page:

<?xml version="1.0" encoding="iso-8859-1"?>
<vxml version="2.0">
  <form id="TrackingInfo">

What follows is the Java code for performing the database query. While a well-structured software system would encapsulate this database access in a method, or perhaps in some representative class, our mission is to produce a basic proof-of-concept. As such we shall resort to in-lining this database code right into our JSP-page enclosed in <% %> delimiters. For those readers uninitiated in JSP, these markers simply indicate that the enclosed Java code should be run on the server at the time of processing the HTTP request. Another benefit to in-lining all of the code into the JSP page is that it allows the casual reader to quickly try out this application. The code shown in Example 4-2 is written to use JDBC drivers for the MySQL relational database. JDBC drivers are available for most popular database products, so porting this to another database would require minimal change.

Example 4-2. The Java code that accessed the package information database
<%  
  //
  // Get tracking number from HTTP post data:
  //
  String trackingNo = request.getParameter("trackingNo");

  //
  // Make JDBC Connection. Perform Query
  //
  Class.forName("org.gjt.mm.mysql.Driver").newInstance();
  java.sql.Connection conn;
  String connurl = 
             "jdbc:mysql://localhost.localdomain/shipping_events";
  String user = "voiceSystem";
  String pw = "secret234password";
  conn = DriverManager.getConnection(connurl,user,pw);
  Statement stmt = conn.createStatement();
  ResultSet res;
  res = stmt.executeQuery("SELECT * FROM event_log " +
                              "where package_id='" +
                              trackingNo + "' order by event_id");
  res.last();    
  int nrows = res.getRow();
%>

You'll notice that we're creating a dynamic SQL query using the variable trackingNo. This variable gets its value from the HTTP request for this page:

String trackingNo = request.getParameter("trackingNo");

You might recall that this value was passed to this JSP by the VoiceXML submit element in the CollectTrackingNo.xml static VoiceXML page:

<submit next="TrackingInfoReporter.jsp" namelist="trackingNo"/>

We're assuming that there is some table or, more likely, some table-view called event_log that contains all of the status event entries for each package currently in transit. As such, whatever mechanism that maintains this table automatically excludes any entries for packages that have already arrived at their destination more than 10 days ago, so we don't have to query every package ever shipped by this company since its founding.

We further assume that the event_id values are assigned chronologically to each status event in this database. This allows us to order our status events chronologically by sorting on event_id, as is done in the SQL query in Example 4-2.

While the mechanics of updating this database are interesting enterprise data management issues, they are beyond the scope of this example. We'll simply assume that we can query the event_log table and get all of the information we want in a timely fashion. We will use Table 4-1 for our testing purposes.

Table 4-1. The contents of the event_log table
event_iddescriptionpackage_idtime_stamp
1Package pickup: New York, NY11112222332002-01-15
2Processing center: New York, NY11112222332002-01-15
3On plane: JFK Airport11112222332002-01-15
4Arrived: LAX Airport11112222332002-01-16
5Processing center: Los Angeles, CA11112222332002-01-16
6On truck: Los Angeles, CA11112222332002-01-16
7Delivered: Los Angeles, CA11112222332002-01-16
8Package pickup: Cleveland, OH09876543212002-01-13
9Processing center: Cleveland09876543212002-01-13
10Processing center: Dayton, OH09876543212002-01-14
11On truck: Dayton, OH09876543212002-01-14
12Failed delivery: Dayton, OH09876543212002-01-14
13Delivered: Dayton, OH09876543212002-01-15

Once we execute our database query, we want to see if it returned any results. If it did, we want to play a simple message introducing the list of status event reports followed by the actual results. The actual results are generated by iterating through the results of our select statement and producing a text-to-speech message with these results. We can produce a block element for each search result, containing a table row massaged to sound like grammatically correct speech. This bit of code is shown in Example 4-3.

Example 4-3. Validating and rendering query results as text-to-speech
<% if(nrows > 0){ %>
     <block>
       <prompt>
         The following events were reported for package number 
         <%=res.getString("package_id") %>
       </prompt>
     </block>        

<%   for(res.first();!res.isAfterLast();res.next()){ %>
       <block>
         <prompt>
           <%=res.getString("descr") %> on 
           <say-as type="date">
             <%=res.getString("time_stamp") %>
           </say-as>
         </prompt>
       </block>
<%   }  %>

We must now consider the case where our query returns nothing, indicating an invalid tracking number. This would fall in the else portion of the if statement:

<% if(nrows > 0){ %>

Our application should simply produce a message indicating that no information could be found for that tracking number. This is shown in Example 4-4.

Example 4-4. Handling an empty query result
<%   }else{ %>
        <block><prompt>
          I couldn't find any information for that package.
        </prompt></block>
<%   } %>  

Lastly, after either providing the caller with the report or stating that the package information could not be found, we want to invite the caller to track another package. This VoiceXML excerpt, shown in Example 4-5, is not dynamic, but our JSP file is as good a place to put it as any.

Example 4-5. The remainder of the Tracking Info Reporter VoiceXML document
    <field name="getAnother" type="boolean">
      <prompt>Would you like to track another package?</prompt>
      <filled>
        <if cond="getAnother==true">
          <goto next="CollectTrackingNumber.xml#CollectTrackingNo"/>
          <else/>
          <prompt>
            Thank you for using the telephone package tracker. 
            Goodbye.
          </prompt>
          <disconnect/>
        </if>
      </filled>
    </field>
  </form>
</vxml>

If we string all of that JSP/VoiceXML code together and put it in a file called TrackingInfoReporter.jsp, we will have completed the JSP portion of this project. Before burdening ourselves with setting up a VoiceXML portal and introducing the telephone-related complexities to our problem, we can first make sure that the Tracking Info Reporter is working simply by visiting it with our Web browser. Enter the URL for the TrackingInfoReporter.jsp followed by ?trackingNo=1111222233, like so:

http://www.BigParcelCompany.com/VoiceApp/
TrackingInfoReporter.jsp?trackingNo=1111222233

This is, more or less, what the VoiceXML portal will send to the server when it executes the submit element. It should return a dynamically generated VoiceXML document similar to that shown in Example 4-6.

Example 4-6. Example output of TrackingInfoReporter.jsp
<?xml version="1.0" encoding="iso-8859-1"?>
<vxml version="2.0">
  <form id="TrackingInfo">
    <block>
      <prompt>
        The following events were reported for package number 
        1111222233
      </prompt>
    </block>        

    <block>
      <prompt>
        Package pickup: New York, NY on 
        <say-as type="date">2002-01-15</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        Processing center: New York, NY on 
        <say-as type="date">2002-01-15</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        On plane: JFK Airport on 
        <say-as type="date">2002-01-15</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        Arrived: LAX Airport on 
        <say-as type="date">2002-01-16</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        Processing center: Los Angeles, CA on 
        <say-as type="date">2002-01-16</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        On truck: Los Angeles, CA on 
        <say-as type="date">2002-01-16</say-as>
      </prompt>
    </block>

    <block>
      <prompt>
        Delivered: Los Angeles, CA on 
        <say-as type="date">2002-01-16</say-as>
      </prompt>
    </block>
  
    <field name="getAnother" type="boolean">
      <prompt>Would you like to track another package?</prompt>
      <filled>
        <if cond="getAnother==true">
          <goto next="CollectTrackingNumber.xml#CollectTrackingNo"/>
          <else/>
          <prompt>
            Thank you for using the telephone package tracker. 
            Goodbye.
          </prompt>
          <disconnect/>
        </if>
      </filled>
    </field>
  </form>
</vxml>

As we can see, our application seems to generate valid VoiceXML based on the contents of our database. We can go ahead and make sure it produces what we think it should produce when the tracking number is not in the database, using this same technique. Once we're convinced that everything is working, we'll point the VoiceXML interpreter at the URL for CollectTrackingNo.xml and try calling in. A possible caller interaction scenario is shown in Example 4-7.

Example 4-7. Caller interaction script
IVR     : Welcome to the telephone package tracking system.
          Please say the 10 digit tracking number.

Caller  : 1111222233

IVR     : The following events were reported 
          for package number 1111222233.
          Package pickup: New York, NY on 2002-01-15.
          Processing center: New York, NY on 2002-01-15.
          On plane: JFK Airport on 2002-01-15.
          Arrived: LAX Airport on 2002-01-16.
          Processing center: Los Angeles, CA on 2002-01-16.
          On truck: Los Angeles, CA on 2002-01-16.
          Delivered: Los Angeles, CA on 2002-01-16.
          Would you like to track another package?

Caller  : No.

IVR     : Thank you for using the telephone package tracker.  
          Goodbye.

This simple example provides an end-to-end demonstration of accessing relational database content through a voice application. The JSP generates an entire VoiceXML document to be executed by a VoiceXML interpreter. The next section will examine a slightly different mode of interaction between the VoiceXML interpreter and dynamic documents where a static VoiceXML application uses tricks to retrieve values from the server.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.87.83