Fatal Error Ocurrs when Subscriber Clicks # - error-handling

I want the where, user clicks on the # and the IVR control goes back to main menu.
But when user clicks on # it say fatal error occurred.
I am newbie in IVR Domain please help me out.
<?xml version='1.0' encoding='iso-8859-1' ?>
<vxml application='http://intx.dev.spokn.com/airtelintx/global.vxml' version='2.0'>
<log expr='[vxml_root_page] This log is after property element' />
<property name='termchar' value=' '></property>
<property name='inputmodes' value='dtmf'></property>
<log expr='[vxml_root_page] This log is after property element' />
<form id='main_menu'>
<var expr='0' name='errorcount' />
<var expr='3' name='maxerrors' />
<field name='ivr_input'>
<grammar mode='dtmf' root='main_choices' type='application/srgs+xml' version='1.0' xml:lang='en-US' xmlns='http://www.w3.org/2001/06/grammar'>
<rule id='main_choices'>
<one-of>
<item>
1
</item>
<item>
2
</item>
<item>
3
</item>
<item>
#
</item>
</one-of>
</rule>
</grammar>
<prompt>
Choose which country you would like to go.
For USA, press 1.
For UK, press 2.
For Canada, press 3.
Press # to return to the main menu.
</prompt>
<nomatch>
<if cond='errorcount == maxerrors'>
<goto next='#exit' />
<else />
<assign expr='errorcount + 1' name='errorcount' />
Oops that was an invalid input
<reprompt />
</if>
</nomatch>
<noinput>
<if cond='errorcount == maxerrors'>
<goto next='#exit' />
<else />
<assign expr='errorcount + 1' name='errorcount' />
No input detected. Please try again.
<reprompt />
</if>
</noinput>
<filled>
<if cond='ivr_input == 1'>
<log expr="'[vxml_reply] ivr_input choice 1, record'" />
<log expr="'[vxml_reply] ivr_input choice 1, record'" />
<log expr="'[vxml_reply] The calling Number callerid'">
<value expr='callerid'></value>
</log>
<submit expr="application.apphost + application.appuri + '/ivr/confirm_country.vxml'" namelist='ivr_input callerid' />
</if>
<if cond='ivr_input == 2'>
<log expr="'[vxml_reply] ivr_input choice 2, record'" />
<log expr="'[vxml_reply] ivr_input choice 2, record'" />
<log expr="'[vxml_reply] The calling Number callerid'">
<value expr='callerid'></value>
</log>
<submit expr="application.apphost + application.appuri + '/ivr/confirm_country.vxml'" namelist='ivr_input callerid' />
</if>
<if cond='ivr_input == 3'>
<log expr="'[vxml_reply] ivr_input choice 3, record'" />
<log expr="'[vxml_reply] ivr_input choice 3, record'" />
<log expr="'[vxml_reply] The calling Number callerid'">
<value expr='callerid'></value>
</log>
<submit expr="application.apphost + application.appuri + '/ivr/confirm_country.vxml'" namelist='ivr_input callerid' />
</if>
<if cond='ivr_input == #'>
<log expr="'[vxml_reply] ivr_input choice #, record'" />
<log expr="'[vxml_reply] ivr_input choice #, record'" />
<log expr="'[vxml_reply] The calling Number callerid'">
<value expr='callerid'></value>
</log>
<submit expr="application.apphost + application.appuri + '/ivr/main_menu.vxml'" namelist='ivr_input callerid' />
</if>
</filled>
</field>
</form>
<error>
<log>
APP ERROR!!!
<value expr='_event' />
</log>
A fatal error occurred. Please contact a customer service representative.
<disconnect />
</error>
<catch event=''>
<log>
UNHANDLED EVENT!!!
<value expr='_event' />
</log>
Sorry, there was a problem processing your request. Please try again later.
<disconnect />
</catch>
</vxml>
I guess this should do the work i.e. assigning termchar value " ", the user can enter # as input.
<property name='termchar' value=' '></property>
I get flowing Error :=
swi:SBjsi|501|SBjsi:ECMAScript engine exception|errmsg=SyntaxError: illegal character|line=1|linetxt=ivr_input == #|tokentxt=#\n

On most platforms the "#" key is a termination character. This can be changed by setting the property "termchar" in you application. If you want to see if the user pressed a "termchar" you can use the shadow variable "termchar" to see what they pressed. For more details on this property and shadow variable you can reference the VoiceXML Specification.

The if condition inside tag should be
<if cond='ivr_input == '#''>
And it works fine. yeah!!!

Related

WSO2 EI: Can I use mediator to request another API and pass its response to the body request?

In my case, I want to add a dynamic value ("Bearer" + {access-token}) to the header mediator .
So before the header mediator, I want to invoke a get-token API and extract {access-token} element from its response. How can I get that ? Thank you so much.
You can achieve such requirements with mediation sequences. You can refer to this blog for more detailed instructions on how to develop a sequence for your requirement. The blog is written for the API Manager product, but nevertheless, you can follow the same to get it done in the EI.
A sample mediation sequence will be as following
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="oauth2-sequence" xmlns="http://ws.apache.org/ns/synapse">
<!-- token generation to the oauth server's token endpoint -->
<!-- add the base64 encoded credentials -->
<property name="client-authorization-header" scope="default" type="STRING" value="MDZsZ3BTMnh0enRhOXBsaXZGUzliMnk4aEZFYTpmdE4yWTdLcnE2SWRsenBmZ1RuTVU1bkxjUFFh" />
<property name="request-body" expression="json-eval($)" scope="default" type="STRING" />
<property name="resource" expression="get-property('axis2', 'REST_URL_POSTFIX')" scope="default" type="STRING" />
<!-- creating a request payload for client_credentials -->
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<root xmlns="">
<grant_type>client_credentials</grant_type>
</root>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args></args>
</payloadFactory>
<!-- set related headers to call the token endpoint -->
<header name="Authorization" expression="fn:concat('Basic ', get-property('client-authorization-header'))" scope="transport" />
<header name="Content-Type" value="application/x-www-form-urlencoded" scope="transport" />
<property name="messageType" value="application/x-www-form-urlencoded" scope="axis2" type="STRING" />
<property name="REST_URL_POSTFIX" value="" scope="axis2" type="STRING" />
<!-- change the token endpoint -->
<call blocking="true">
<endpoint>
<http method="POST" uri-template="https://localhost:9443/oauth2/token" />
</endpoint>
</call>
<!-- append the acquired access token and make the call to the backend service -->
<property name="bearer-token" expression="json-eval($.access_token)" scope="default" type="STRING" />
<property name="REST_URL_POSTFIX" expression="get-property('resource')" scope="axis2" type="STRING" />
<header name="Authorization" expression="fn:concat('Bearer ', get-property('bearer-token'))" scope="transport" />
<payloadFactory media-type="json">
<format>$1</format>
<args>
<arg evaluator="xml" expression="get-property('request-body')" />
</args>
</payloadFactory>
<!-- perform a send or call to complete the execution of the backend service call in EI -->
</sequence>
Hope this helps you to start with implementation.

Splitter group attribute inject variable parameter

can you inject a value from the config params file in to the splitter group attribute? if so, what is the proper way of doing it? thanks!
I've tried,
<split streaming="true" >
<tokenize token="\n" group="{{noOfLines}}" />
<log message="Split Group Body: ${body}"/>
<to uri="bean:extractHeader" />
<to id="acceptedFileType" ref="pConsumer" />
</split>
<split streaming="true" >
<tokenize token="\n" group={{noOfLines}} />
<log message="Split Group Body: ${body}"/>
<to uri="bean:extractHeader" />
<to id="acceptedFileType" ref="pConsumer" />
</split>
what am I doing wrong?
ERROR: 'Open quote is expected for attribute "group" associated with an element type "tokenize".
<tokenize token="\n" group="<simple>${properties:noOfLines:500}</simple>" />
ERROR: 'The value of attribute "group" associated with an element type "tokenize" must not contain the '<' character.'
<tokenize token="\n" group="${properties:noOfLines:500}" />
Caused by: org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: '${properties:noOfLines:500}' is not a valid value for 'integer'.
my quest for info and answers didn't go deep enough. I found this was already encounted and answered by Claus Ibsen. Please see if you run in to this need.
Validation error with integer property (camel)
http://camel.apache.org/using-propertyplaceholder.html
under section "Using Property Placeholders for Any Kind of Attribute in the XML DSL"
here is what I did following these instructions.
added property prefix namespace
xmlns:prop="http://camel.apache.org/schema/placeholder"
then modified the tokenize attribute
<tokenize token="\n" prop:group="noOfLines" />
I'm using the property placeholder
<cm:property-placeholder persistent-id="com.digital.passthru.core" />
this works like a charm. thank you Claus.
this is what worked for me.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:prop="http://camel.apache.org/schema/placeholder"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint
http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cm:property-placeholder persistent-id="com.ge.digital.passthru.core" />
<bean id="deadLetterErrorHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
<property name="deadLetterUri" value="${deadLetterQueue}"/>
<property name="redeliveryPolicy" ref="redeliveryPolicyConfig"/>
<property name="useOriginalMessage" value="true" />
</bean>
<bean id="redeliveryPolicyConfig" class="org.apache.camel.processor.RedeliveryPolicy">
<property name="maximumRedeliveries" value="3"/>
<property name="redeliveryDelay" value="5000" />
</bean>
...
<camelContext
id="com.ge.digital.passthru.coreCamelContext"
trace="true"
xmlns="http://camel.apache.org/schema/blueprint"
allowUseOriginalMessage="false"
streamCache="true"
errorHandlerRef="deadLetterErrorHandler" >
...
<route
id="core.predix.accept.file.type.route"
autoStartup="true" >
<from uri="{{fileEntranceEndpoint}}" />
<convertBodyTo type="java.lang.String" />
<split streaming="true" strategyRef="csvAggregationStrategy">
<tokenize token="\n" />
<process ref="toCsvFormat" /> <!-- passthru only we do not allow embedded commas in numeric data -->
</split>
<log message="CSV body: ${body}" loggingLevel="INFO"/>
<choice>
<when>
<simple>${header.CamelFileName} regex '^.*\.(csv|CSV|txt|gpg)$'</simple>
<log message="${file:name} accepted for processing..." />
<choice>
<when>
<simple>${header.CamelFileName} regex '^.*\.(CSV|txt|gpg)$'</simple>
<setHeader headerName="CamelFileName">
<!-- <simple>${file:name.noext}.csv</simple> --> <!-- file:name.noext.single -->
<simple>${file:name.noext.single}.csv</simple>
</setHeader>
<log message="${file:name} changed file name." />
</when>
</choice>
<split streaming="true" >
<tokenize token="\n" prop:group="noOfLines" />
<log message="Split Group Body: ${body}"/>
<to uri="bean:extractHeader" />
<to id="acceptedFileType" ref="predixConsumer" />
</split>
<to uri="bean:extractHeader?method=cleanHeader"/>
</when>
<otherwise>
<log message="${file:name} is an unknown file type, sending to unhandled repo." loggingLevel="INFO" />
<to uri="{{unhandledArchive}}" />
</otherwise>
</choice>
</route>
...
and noOfLines is a property
now there is an order to all this as I found out while doing this also.
please go to the link below for the Camel ordering of components in XML DSL
Camel DataFormat Jackson using blueprint XML DSL throws context exception

WSO2 ESB: Display dataService response

How do you display the response returned by calling a webservice endpoint on a sequence?
Below is the sequence that I use. I would like to display the return value from the dataservice called "CDServiceEndpoint" on the wso2carbon.log. Is that possible? If not, how can I get the data displayed.
<sequence xmlns="http://ws.apache.org/ns/synapse" name="ConcurGetADPExtractFlow" onError="GeneralErrorHandler">
<property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" name="current-context-details" expression="concat(get-property('current-context-details'), ', ConcurGetADPExtractFlow')" />
<property name="scenario" value="ConcurGetADPExtractFlow" />
<log level="custom">
<property name="DEBUGGING" value="ConcurGetADPExtractFlow" />
<property name="start-date" value="2015-02-23" />
<property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" name="End Date" expression="get-property('current-date')" />
</log>
<xslt key="Concur_Get_ADP_Extract_Transformation">
<property name="start-date" value="2015-03-02" />
<property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" name="end-date" expression="get-property('current-date')" />
</xslt>
<property name="post-data-service-sequence" value="ConcurTransformADPExtractFlow" />
<property name="OUT_ONLY" value="false" />
<send receive="DataServiceInvocationErrorFlow">
<endpoint key="ConcurDataServiceEndpoint" />
</send>
<description>Sends a request to the data service for the ADP extract data.</description>
</sequence>
Below is how my DataServiceInvocationErrorFlow looks like.
<sequence xmlns="http://ws.apache.org/ns/synapse" name="DataServiceInvocationErrorFlow">
<filter xmlns:ns="http://org.apache.synapse/xsd" xmlns:m="http://ws.wso2.org/dataservice" xmlns:ns3="http://org.apache.synapse/xsd" xpath="//m:DataServiceFault">
<then>
<log level="custom">
<property name="status" value="data-service-fault" />
</log>
<property name="error_message" expression="//m:DataServiceFault" />
<sequence key="GeneralErrorHandler" />
<drop />
</then>
<else>
<filter source="string-length(get-property('ERROR_MESSAGE'))" regex="0.0">
<then>
<filter xpath="//soapenv:Fault">
<then>
<log level="custom">
<property name="status" value="ERROR" />
</log>
<property name="error_message" expression="//soapenv:Fault" />
<sequence key="GeneralErrorHandler" />
<drop />
</then>
<else>
<log level="custom">
<property name="status" value="success response from DSS" />
</log>
<filter source="string-length(normalize-space(get-property('post-data-service-sequence')))" regex="0.0">
<then />
<else>
<property name="temp-post-data-service-sequence" expression="get-property('post-data-service-sequence')" />
<property name="post-data-service-sequence" value="" />
<sequence key="{get-property('temp-post-data-service-sequence')}" />
</else>
</filter>
</else>
</filter>
</then>
<else>
<property name="error_message" expression="get-property('ERROR_MESSAGE')" />
<sequence key="GeneralErrorHandler" />
<drop />
</else>
</filter>
</else>
</filter>
</sequence>
If by CDServiceEndpoint you meant ConcurDataServiceEndpoint, then you are already handling the response from that endpoint in your DataServiceInvocationErrorFlow sequence that you defined on the Send mediator, which by the way is confusingly named, since your receive sequence will run no matter if you get an error response or a good one. All you need to do is log it inside DataServiceInvocationErrorFlow using Log mediator.
Had you not defined a receive sequence on your Send mediator, the response would have gotten to your outSequence, where you can log it with Log mediator too.

How to disable VXML to "catch event" (nomatch) for specific DTML

The VXML menu has the options 1, 2, 3, 9, and '#'. The customers will assume that if they press 0, it would take them to the transfer to service center.
But 0 in this menu won't take them to service center, the requirement is to ignore 0 DTMF and keep playing the prompt without warning them.
This menu's bargien property has to be true. I am required to make the prompt menu where users are able to press any mentioning DTMF above to interrupt it and goto next, but I have to set the program to ignore DTMF 0.
Please try this code.
Key point is "bargeintype" property and grammar rule.
VXML's form
<form id="sample">
<field name="menu_result">
<property name="bargein" value="true" />
<property name="bargeintype" value="hotword" /><!-- Important! -->
<property name="inputmodes" value="dtmf" />
<property name="timeout" value="5s" />
<property name="interdigittimeout" value="0s" />
<property name="termchar" value="D" />
<prompt>
Please push either of 1, 2, 3, 9 or pound sign button.
Other button is ignored.
</prompt>
<grammar src="special_menu.grxml" />
<filled>
<assign name="result" expr="menu_result.slice(-1)"/><!-- Get last 1 digit -->
<goto next="#next_form"/>
</filled>
<noinput><prompt>No input error.</prompt></noinput>
<nomatch><prompt>No match error.</prompt></nomatch>
</field>
</form>
special_menu.grxml
<?xml version="1.0" encoding="UTF-8"?>
<grammar
version="1.0"
mode="dtmf"
root="main"
xmlns="http://www.w3.org/2001/06/grammar"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rule id="main">
<item repeat="0-">
<one-of><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>*</item></one-of>
</item>
<one-of>
<item>1</item><item>2</item><item>3</item><item>9</item><item>#</item>
</one-of>
</rule>
</grammar>

How to make a dynamic xPath and execute it?

I collect string to xpath
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
and I want to run this xpath and write the value of a Property
<property name="KEY" expression="get-property('xPathElemet')"/>
but receive only collected a string
how to xpath of the Property?
example code sequence :
<iterate continueParent="true" expression="//t:Employee">
<target>
<sequence>
<call-template target="save_element">
<with-param name="key_element" value="Name"/>
</call-template>
</sequence>
</target>
</iterate>
example code template :
<template xmlns="http://ws.apache.org/ns/synapse" name="save_element">
<parameter name="key_element"/> <!--example: "Name"-->
<sequence>
<property name="KEY" expression="fn:concat(//t:Employee/t:SNILS, ':' ,$func:key_element)" scope="default"
type="STRING"/> <!--example: "111-111-111-1:Name"-->
<property name="xPathElemet" expression="fn:concat('//t:Employee/t:', $func:element)"/> <!--example: "//t:Employee/t:Name"-->
<property name="VALUE" expression="get-property('xPathElemet')" scope="default" type="STRING"/> <!--example: Den (Now it does not work)-->
<dbreport>
<connection>
<pool>
<seetings/>
</pool>
</connection>
<statement>
<sql>
<![CDATA[insert into cache( key , value ) values (?, ?);]]></sql> <!--insert new line where key = "111-111-111-1:Name" and value = "Den"-->
<parameter expression="get-property('KEY')" type="VARCHAR"/>
<parameter expression="get-property('VALUE')" type="VARCHAR"/>
</statement>
</dbreport>
</sequence>
</template>
example xml:
<Employees xmlns="https://services">
<Employee>
<SNILS>111-111-111-1</SNILS>
<Name>Den</Name>
</Employee>
<Employee>
<SNILS>111-111-111-2</SNILS>
<Name>Elena</Name>
</Employee>
</Employees>
Use evaluate
In your case:
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
<property name="KEY" expression="evaluate(get-property('xPathElemet'))"/>
You can find more infomation in this blog.
Please try the following and see if it works
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
<property xmlns:t="https://services" name="xPathfull" expression="fn:concat(get-property('xPathElemet'),'/text()')"/>
<property name="KEY" expression="get-property('xPathfull')"/>
What was missing from your code was the /text() which refer to the parameters of the given xpath. Please try this