📄 vxi.cpp
字号:
}
}
catch (const VXIException::InterpreterEvent & e) {
DoEvent(documentRoot, e);
throw VXIException::Exit(NULL);
}
}
void VXI::PerformTransition(const VXMLElement & elem,
const vxistring & rawURI,
VXIMap * rawSubmitData,
bool isSubdialog,
bool isSubmitElement)
{
if (log->IsLogging(2)) {
log->StartDiagnostic(2) << L"VXI::PerformTransition(" << rawURI << L")";
log->EndDiagnostic();
}
VXIMapHolder submitData(rawSubmitData);
// (1) Determine fetch properties for document load.
// (1.1) Create empty fetch object. Now we need to fill this in.
VXIMapHolder fetchobj;
if (fetchobj.GetValue() == NULL) throw VXIException::OutOfMemory();
// (1.2) Set URIs for the Jump.
vxistring uri((rawURI.empty() ? L"" : rawURI));
vxistring fragment;
const VXIchar * tempStr = L"";
// (1.2.1) Divide raw URI into uri + fragment.
exe->properties.GetFetchobjURIs(elem, fetchobj, uri, fragment);
// (1.2.2) Handle the degenerate case.
if (uri.empty() && fragment.empty()) {
log->StartDiagnostic(0) << L"VXI::PerformTransition - invalid URI, \""
<< (rawURI.empty() ? L"NULL" : rawURI.c_str()) << L"\"";
log->EndDiagnostic();
throw VXIException::InterpreterEvent(EV_ERROR_BADURI);
}
// (1.2.3) In the fragment only case, just go to the indicated item.
if (uri.empty()) {
VXMLElement targetElement = FindDialog(elem, fragment);
if (targetElement == 0) {
log->StartDiagnostic(0) << L"VXI::PerformTransition - non-existent "
L"dialog, \"" << (rawURI.empty() ? L"NULL" : rawURI.c_str()) << L"\"";
log->EndDiagnostic();
throw VXIException::InterpreterEvent(EV_ERROR_BADDIALOG);
}
if (!isSubdialog)
throw JumpDialog(targetElement);
else {
//#pragma message("CC - temporarily pop the last field properties so that subdialog won't complain")
PropertyList subprop(exe->properties);
subprop.PopPropertyLevel(FIELD_PROP);
vxistring absoluteURI(L"");
tempStr = exe->properties.GetProperty(PropertyList::AbsoluteURI);
if (tempStr) absoluteURI = tempStr;
throw JumpDoc(exe->platDefaults, exe->application, exe->applicationURI,
exe->document, absoluteURI, targetElement, isSubdialog, isSubmitElement,
subprop);
}
}
//#pragma message ("VXI::PerformTransition - ignoring fetchhint")
// (1.3) Get remaining fetch properties. At this point, we now need
// to assemble seperate fetch properties for fetchaudio, up
// until now all the prep work is identical.
VXIMapHolder fetchAudioFetchobj(NULL);
fetchAudioFetchobj = fetchobj;
if (fetchAudioFetchobj.GetValue() == NULL) throw VXIException::OutOfMemory();
exe->properties.GetFetchobjCacheAttrs(elem, PropertyList::Document,fetchobj);
exe->properties.GetFetchobjCacheAttrs(elem, PropertyList::Audio,
fetchAudioFetchobj);
if (submitData.GetValue() != NULL) {
if (!exe->properties.GetFetchobjSubmitAttributes(elem, submitData,
fetchobj))
{
// This should never occur.
log->StartDiagnostic(0) << L"VXI::PerformTransition - couldn't set "
L"the submit attributes.";
log->EndDiagnostic();
throw VXIException::InterpreterEvent(EV_ERROR_BADURI);
}
submitData.Release(); // This map is now owned by fetchobj.
}
// (2) Load Document.
// (2.1) Start fetch audio.
vxistring fetchaudio;
if (!elem.GetAttribute(ATTRIBUTE_FETCHAUDIO, fetchaudio))
fetchaudio = toString(exe->properties.GetProperty(L"fetchaudio"));
if (!fetchaudio.empty()) {
// Get All properties for fetching audio
VXIMapHolder fillerProp(VXIMapClone(fetchAudioFetchobj.GetValue()));
exe->properties.GetProperties(fillerProp);
pm->PlayAll(); // Finish playing already queued prompts
pm->PlayFiller(fetchaudio, fillerProp);
}
// (2.2) Load document and verify that dialog exists.
// (2.2.1) Load the VoiceXML document.
VXMLDocument document;
VXMLElement documentDialog;
VXIMapHolder documentFetchProps;
AttemptDocumentLoad(uri, fetchobj, document, documentFetchProps);
// (2.2.2) If there was a fragment, does the named dialog exist?
VXMLElement documentRoot = document.GetRoot();
documentDialog = FindDialog(documentRoot, fragment);
if (documentDialog == 0) {
if (fragment.empty())
log->StartDiagnostic(0) << L"VXI::PerformTransition - no dialog "
L"element found in \"" << uri << L"\"";
else
log->StartDiagnostic(0) << L"VXI::PerformTransition - named dialog, "
<< fragment << L" not found in \"" << uri
<< L"\"";
log->EndDiagnostic();
throw VXIException::InterpreterEvent(EV_ERROR_BADDIALOG);
}
// (3) Get Document language & find associated defaults.
// (3.1) Create a new property list containing the document properties.
PropertyList newProperties(*log);
//#pragma message("JC: This should set from * then override with specific")
//#pragma message("JC: Make sure this returns the specific (if present) at the end")
// WARNING: The defaults document has multiple languages and a language-independent '*' group.
// This should really read the '*' group and then overlay the set specific to the active language.
// (3.2) Extract the language setting.
const VXIchar * language = newProperties.GetProperty(PropertyList::Language);
if (language == NULL) language = GENERIC_DEFAULTS;
// (3.3) Find the language defaults.
VXMLElement defaults;
VXMLElement defaultsRoot = domDefaultDoc.GetRoot();
for (VXMLNodeIterator it(defaultsRoot); it; ++it) {
VXMLNode child = *it;
// Look for a language node.
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child);
if (elem.GetName() != DEFAULTS_LANGUAGE) continue;
vxistring id;
elem.GetAttribute(ATTRIBUTE_ID, id);
if (id == language || (id == GENERIC_DEFAULTS && defaults == 0))
defaults = elem;
}
if (defaults != 0)
newProperties.SetProperties(defaults, DEFAULTS_PROP, VXIMapHolder(NULL));
newProperties.SetProperties(documentRoot, DOC_PROP, documentFetchProps);
// newProperties should now contain the properties from the platform defaults plus
// the properties at document level.
// (3.4) Copy the document properties in and find the absolute URI.
vxistring absoluteURI(L"");
vxistring applicationURI(L"");
newProperties.SetProperties(documentRoot, DOC_PROP, documentFetchProps);
tempStr = newProperties.GetProperty(PropertyList::AbsoluteURI, DOC_PROP);
if (tempStr == NULL)
absoluteURI = uri.empty() ? L"" : uri.c_str();
else
absoluteURI = tempStr;
// (4) Load the application.
VXMLDocument application;
VXIMapHolder appProperties;
// (4.1) Get the application URI.
vxistring appuri;
documentRoot.GetAttribute(ATTRIBUTE_APPLICATION, appuri);
if (!appuri.empty()) {
// (4.2) Initialize application fetch parameters.
VXIMapHolder appFetchobj;
if (appFetchobj.GetValue() == NULL)
throw VXIException::OutOfMemory();
vxistring appFragment;
newProperties.GetFetchobjURIs(documentRoot, appFetchobj, appuri,
appFragment);
if (appuri.empty()) {
log->LogError(214);
throw VXIException::InterpreterEvent(EV_ERROR_APP_BADURI);
}
newProperties.GetFetchobjCacheAttrs(documentRoot, PropertyList::Document,
appFetchobj);
// (4.3) Load the application and its properties (we must then restore the
// document properties.
AttemptDocumentLoad(appuri, appFetchobj, application, appProperties);
// (4.3.1) If an application root document specifies an application root
// element error.semantic is thrown.
VXMLElement documentRootCheck = application.GetRoot();
vxistring appuriCheck;
documentRootCheck.GetAttribute(ATTRIBUTE_APPLICATION, appuriCheck);
if (!appuriCheck.empty())
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC,
L"application root element presents in application root document");
newProperties.SetProperties(application.GetRoot(), APP_PROP, appProperties);
// (4.4) Get the absolute URI for the application root.
tempStr = newProperties.GetProperty(PropertyList::AbsoluteURI, APP_PROP);
applicationURI = (tempStr == NULL ? L"" : tempStr);
}
// (5) Generate the final event.
throw JumpDoc(defaults, application, applicationURI,
document, absoluteURI, documentDialog, isSubdialog,
isSubmitElement, newProperties);
}
// Finds the named dialog in the document. If the name is empty, the first
// item is returned.
//
VXMLElement VXI::FindDialog(const VXMLElement & start, const vxistring & name)
{
if (log->IsLogging(2)) {
log->StartDiagnostic(2) << L"VXI::FindDialog(" << name << L")";
log->EndDiagnostic();
}
// (0) find the root node.
VXMLElement doc;
for (doc = start; doc != 0 && doc.GetName() != NODE_VXML;
doc = doc.GetParent());
if (doc == 0) return VXMLElement();
// (1) Walk through all elements at this level and find match.
for (VXMLNodeIterator it(doc); it; ++it) {
VXMLNode child = *it;
// (1.1) Only <form> & <menu> elements are considered.
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child);
VXMLElementType nodeName = elem.GetName();
if (nodeName != NODE_FORM && nodeName != NODE_MENU) continue;
// (1.2) If no dialog was specified, return the first one.
if (name.empty()) return elem;
// (1.3) Otherwise, look for an exact match.
vxistring id;
if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, id)) continue;
if (name == id)
return elem;
}
// (2) User attempted to GOTO to non-existant dialog or have an empty doc!
log->LogDiagnostic(2, L"VXI::FindDialog - no match found.");
return VXMLElement();
}
//#############################################################################
// Document Loop
//#############################################################################
// return success/failure (can't throw error here as caller needs
// a chance to clean up
// Also initialize new context (session scope)
bool VXI::PushExecutionContext(const vxistring & sessionScript)
{
log->LogDiagnostic(2, L"VXI::PushExecutionContext()");
// (1) Catch recursive <subdialog> case...
if (stackDepth >= DEFAULT_MAX_EXE_STACK_DEPTH) {
log->LogError(211);
return false;
}
// (2) Create new execution context.
ExecutionContext * ep = new ExecutionContext(rec, jsi, *log, exe);
if (ep == NULL) throw VXIException::OutOfMemory();
exe = ep;
++stackDepth;
// (3) Init new context from channel (i.e. set up 'session' scope)
exe->script.PushScope(SCOPE_Session);
if (!sessionScript.empty()) exe->script.EvalScript(sessionScript);
exe->script.SetVarReadOnly(SCOPE_Session);
log->LogDiagnostic(2, L"VXI::PushExecutionContext - session variables "
L"initialized");
// (4) Init new context defaults (i.e. set up platform defaults)
// (4.1) Find generic language properties.
VXMLElement defaultsRoot = domDefaultDoc.GetRoot();
for (VXMLNodeIterator it(defaultsRoot); it; ++it) {
VXMLNode child = *it;
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child);
if (elem.GetName() != DEFAULTS_LANGUAGE) continue;
vxistring id;
elem.GetAttribute(ATTRIBUTE_ID, id);
if (id != GENERIC_DEFAULTS) continue;
exe->platDefaults = elem;
break;
}
if (exe->platDefaults == 0) {
log->LogError(223);
PopExecutionContext();
return false;
}
// (4.2) Install defaults. We only need to worry about the properties (for
// document load) and the ECMA variables and scripts (for catch handlers on
// load failure). The grammars & prompts may be safely ignored.
exe->properties.SetProperties(exe->platDefaults, DEFAULTS_PROP,
VXIMapHolder());
exe->script.PushScope(SCOPE_Defaults);
ProcessRootScripts(exe->platDefaults);
log->LogDiagnostic(2, L"VXI::PushExecutionContext - platform defaults "
L"initialized");
return true;
}
void VXI::PopExecutionContext()
{
if (exe == NULL) return;
ExecutionContext * current = exe;
exe = current->next;
--stackDepth;
delete current;
}
void VXI::AttemptDocumentLoad(const vxistring & uri,
const VXIMapHolder & uriProperties,
VXMLDocument & doc,
VXIMapHolder & docProperties,
bool isDefaults)
{
// (1) Create map to store document properties.
if (docProperties.GetValue() == NULL)
throw VXIException::OutOfMemory();
// (2) Fetch the document
VXIbyte *cbuffer = NULL;
VXIulong bufferSize = 0;
int result = parser->FetchDocument(uri.c_str(), uriProperties, inet, cache,
*log, doc, docProperties, isDefaults,
&cbuffer, &bufferSize);
// If we didn't have a parse error, dump the VoiceXML document if
// configured to do so, otherwise free the content buffer
if ((result != 4) && (cbuffer)) {
VXIString *key = NULL, *value = NULL;
if ((log->IsLogging(SimpleLogger::DOC_DUMPS)) &&
(log->LogContent(VXI_MIME_XML, cbuffer, bufferSize, &key, &value))) {
vxistring diagUri(uri);
const VXIValue * val = VXIMapGetProperty(docProperties.GetValue(),
INET_INFO_ABSOLUTE_NAME);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -