Author: sayer
Date: 2009-10-22 02:53:24 +0200 (Thu, 22 Oct 2009)
New Revision: 1554

Added:
   trunk/apps/dsm/doc/examples/test_exception.dsm
Modified:
   trunk/apps/dsm/DSMChartReader.cpp
   trunk/apps/dsm/DSMChartReader.h
   trunk/apps/dsm/DSMCoreModule.cpp
   trunk/apps/dsm/DSMCoreModule.h
   trunk/apps/dsm/DSMStateEngine.cpp
   trunk/apps/dsm/DSMStateEngine.h
   trunk/apps/dsm/doc/Readme.dsm.txt
Log:
DSM exceptions. SEMS-59.

actions and conditions should be able to throw exceptions. if an exceptions 
happens, execution of the current actions is interrupted, and special exception 
transitions are executed. 



Modified: trunk/apps/dsm/DSMChartReader.cpp
===================================================================
--- trunk/apps/dsm/DSMChartReader.cpp   2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMChartReader.cpp   2009-10-22 00:53:24 UTC (rev 1554)
@@ -340,6 +340,7 @@
        }
 
        tr->precond = cl->conditions;
+       tr->is_exception = cl->is_exception;
        delete cl;
 
        // start AL_trans action list
@@ -354,6 +355,11 @@
        continue;
       }
 
+      if (token == "exception") {
+       cl->is_exception = true;
+       continue;
+      }
+      
       //       DBG("new condition: '%s'\n", token.c_str());
       DSMCondition* c = conditionFromToken(token, cl->invert_next);
       cl->invert_next = false;

Modified: trunk/apps/dsm/DSMChartReader.h
===================================================================
--- trunk/apps/dsm/DSMChartReader.h     2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMChartReader.h     2009-10-22 00:53:24 UTC (rev 1554)
@@ -69,9 +69,10 @@
 };
 
 struct DSMConditionList : public DSMElement {
- DSMConditionList() : invert_next(false) { }
+ DSMConditionList() : invert_next(false), is_exception(false) { }
   vector<DSMCondition*> conditions;
   bool invert_next;
+  bool is_exception;
 };
 
 class DSMChartReader {

Modified: trunk/apps/dsm/DSMCoreModule.cpp
===================================================================
--- trunk/apps/dsm/DSMCoreModule.cpp    2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMCoreModule.cpp    2009-10-22 00:53:24 UTC (rev 1554)
@@ -44,6 +44,8 @@
   DEF_CMD("callFSM", SCCallFSMAction);
   DEF_CMD("returnFSM", SCReturnFSMAction);
 
+  DEF_CMD("throw", SCThrowAction);
+
   DEF_CMD("stop", SCStopAction);
 
   DEF_CMD("playPrompt", SCPlayPromptAction);
@@ -257,6 +259,29 @@
   sess->setDtmfDetectionEnabled(false);
 } EXEC_ACTION_END;
 
+CONST_ACTION_2P(SCThrowAction, ',', true);
+EXEC_ACTION_START(SCThrowAction) {
+  map<string, string> e_args;
+  e_args["type"] = resolveVars(par1, sess, sc_sess, event_params); 
+  DBG("throwing DSMException type '%s'\n", e_args["type"].c_str());
+
+  string e_params = resolveVars(par2, sess, sc_sess, event_params);
+  
+  // inefficient param-split
+  vector<string> params = explode(e_params, ";");
+  for (vector<string>::iterator it=
+        params.begin(); it != params.end(); it++) {
+    vector<string> n = explode(*it, "=");
+    if (n.size()==2) {
+      e_args[n[0]]=n[1];
+    }
+  }
+  
+  throw DSMException(e_args);
+
+} EXEC_ACTION_END;
+
+
 EXEC_ACTION_START(SCStopAction) {
   if (resolveVars(arg, sess, sc_sess, event_params) == "true") {
     DBG("sending bye\n");

Modified: trunk/apps/dsm/DSMCoreModule.h
===================================================================
--- trunk/apps/dsm/DSMCoreModule.h      2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMCoreModule.h      2009-10-22 00:53:24 UTC (rev 1554)
@@ -70,6 +70,7 @@
 DEF_SCModSEStrArgAction(SCCallFSMAction);
 DEF_SCModSEStrArgAction(SCReturnFSMAction);
 
+DEF_ACTION_2P(SCThrowAction);
 
 DEF_ACTION_2P(SCSetAction);
 DEF_ACTION_2P(SCAppendAction);

Modified: trunk/apps/dsm/DSMStateEngine.cpp
===================================================================
--- trunk/apps/dsm/DSMStateEngine.cpp   2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMStateEngine.cpp   2009-10-22 00:53:24 UTC (rev 1554)
@@ -156,9 +156,9 @@
 }
 
 bool DSMStateEngine::runactions(vector<DSMAction*>::iterator from, 
-                            vector<DSMAction*>::iterator to, 
-                            AmSession* sess,  DSMCondition::EventType event,
-                            map<string,string>* event_params,  bool& 
is_consumed) {
+                               vector<DSMAction*>::iterator to, 
+                               AmSession* sess,  DSMCondition::EventType event,
+                               map<string,string>* event_params,  bool& 
is_consumed) {
 //   DBG("running %zd actions\n", to - from);
   for (vector<DSMAction*>::iterator it=from; it != to; it++) {
     DBG("executing '%s'\n", (*it)->name.c_str()); 
@@ -205,11 +205,19 @@
 bool DSMStateEngine::init(AmSession* sess, const string& startDiagram, 
                          DSMCondition::EventType init_event) {
 
-  if (!jumpDiag(startDiagram, sess, init_event, NULL)) {
-    ERROR("initializing with start diag '%s'\n",
-         startDiagram.c_str());
-    return false;
-  }  
+  try {
+    if (!jumpDiag(startDiagram, sess, init_event, NULL)) {
+      ERROR("initializing with start diag '%s'\n",
+           startDiagram.c_str());
+      return false;
+    }
+  } catch (DSMException& e) {
+    DBG("Exception type '%s' occured while initializing! Run init event as 
exception...\n", 
+       e.params["type"].c_str());
+    runEvent(sess, init_event, &e.params, true);
+    return true;
+    
+  }
 
   DBG("run init event...\n");
   runEvent(sess, init_event, NULL);
@@ -245,98 +253,119 @@
 }
 
 void DSMStateEngine::runEvent(AmSession* sess,
-                          DSMCondition::EventType event,
-                          map<string,string>* event_params) {
+                             DSMCondition::EventType event,
+                             map<string,string>* event_params,
+                             bool run_exception) {
   if (!current || !current_diag)
     return;
+  
+  DSMCondition::EventType active_event = event;
+  map<string,string>* active_params = event_params;
+  map<string,string> exception_params;
+  bool is_exception = run_exception;
 
   bool is_consumed = true;
   do {
-    is_consumed = true;
+    try {
+      is_consumed = true;
 
-    for (vector<DSMTransition>::iterator tr = current->transitions.begin();
-        tr != current->transitions.end();tr++) {
-      DBG("checking transition '%s'\n", tr->name.c_str());
-      
-      vector<DSMCondition*>::iterator con=tr->precond.begin();
-      while (con!=tr->precond.end()) {
-       if (!(*con)->_match(sess, event, event_params))
-         break;
-       con++;
-      }
-      if (con == tr->precond.end()) {
-       DBG("transition '%s' matched.\n", tr->name.c_str());
+      for (vector<DSMTransition>::iterator tr = current->transitions.begin();
+          tr != current->transitions.end();tr++) {
+       if (tr->is_exception != is_exception)
+         continue;
        
-       //  matched all preconditions
-       // find target state
-       State* target_st = current_diag->getState(tr->to_state);
-       if (!target_st) {
-         ERROR("script writer error: transition '%s' from "
-               "state '%s' to unknown state '%s'\n",
-               tr->name.c_str(),
-               current->name.c_str(),
-               tr->to_state.c_str());
-       }
+       DBG("checking transition '%s'\n", tr->name.c_str());
        
-       // run post-actions
-       if (current->post_actions.size()) {
-         DBG("running %zd post_actions of state '%s'\n",
-             current->post_actions.size(), current->name.c_str());
-         if (runactions(current->post_actions.begin(), 
-                        current->post_actions.end(), 
-                        sess, event, event_params, is_consumed)) {
+       vector<DSMCondition*>::iterator con=tr->precond.begin();
+       while (con!=tr->precond.end()) {
+         if (!(*con)->_match(sess, active_event, active_params))
            break;
+         con++;
+       }
+       if (con == tr->precond.end()) {
+         DBG("transition '%s' matched.\n", tr->name.c_str());
+         
+         //  matched all preconditions
+         // find target state
+         State* target_st = current_diag->getState(tr->to_state);
+         if (!target_st) {
+           ERROR("script writer error: transition '%s' from "
+                 "state '%s' to unknown state '%s'\n",
+                 tr->name.c_str(),
+                 current->name.c_str(),
+                 tr->to_state.c_str());
          }
-       }
-       
-       // run transition actions
-       if (tr->actions.size()) {
-         DBG("running %zd actions of transition '%s'\n",
-             tr->actions.size(), tr->name.c_str());
-         if (runactions(tr->actions.begin(), 
-                        tr->actions.end(), 
-                        sess, event, event_params, is_consumed)) {
+         
+         // run post-actions
+         if (current->post_actions.size()) {
+           DBG("running %zd post_actions of state '%s'\n",
+               current->post_actions.size(), current->name.c_str());
+           if (runactions(current->post_actions.begin(), 
+                          current->post_actions.end(), 
+                          sess, active_event, active_params, is_consumed)) {
+             break;
+           }
+         }
+         
+         // run transition actions
+         if (tr->actions.size()) {
+           DBG("running %zd actions of transition '%s'\n",
+               tr->actions.size(), tr->name.c_str());
+           if (runactions(tr->actions.begin(), 
+                          tr->actions.end(), 
+                          sess, active_event, active_params, is_consumed)) {
+             break;
+           }
+         }
+         
+         // go into new state
+         if (!target_st) {
            break;
          }
-       }
-       
-       // go into new state
-       if (!target_st) {
-         break;
-       }
-       DBG("changing to new state '%s'\n", target_st->name.c_str());
-       MONITORING_LOG(sess->getLocalTag().c_str(), "dsm_state", 
target_st->name.c_str());
-
+         DBG("changing to new state '%s'\n", target_st->name.c_str());
+         
 #ifdef USE_MONITORING
-       if (DSMFactory::MonitoringFullTransitions) {
-         MONITORING_LOG_ADD(sess->getLocalTag().c_str(), 
-                            "dsm_stategraph", 
-                            ("> "+ tr->name + " >").c_str());
-       }
-
-       if (DSMFactory::MonitoringFullCallgraph) {
-         MONITORING_LOG_ADD(sess->getLocalTag().c_str(), 
-                            "dsm_stategraph", 
-                            (current_diag->getName() +"/"+ 
target_st->name).c_str());
-       }
+         MONITORING_LOG(sess->getLocalTag().c_str(), "dsm_state", 
target_st->name.c_str());
+         
+         if (DSMFactory::MonitoringFullTransitions) {
+           MONITORING_LOG_ADD(sess->getLocalTag().c_str(), 
+                              "dsm_stategraph", 
+                              ("> "+ tr->name + " >").c_str());
+         }
+         
+         if (DSMFactory::MonitoringFullCallgraph) {
+           MONITORING_LOG_ADD(sess->getLocalTag().c_str(), 
+                              "dsm_stategraph", 
+                              (current_diag->getName() +"/"+ 
target_st->name).c_str());
+         }
 #endif
-
-       current = target_st;
-       
-       // execute pre-actions
-       if (current->pre_actions.size()) {
-         DBG("running %zd pre_actions of state '%s'\n",
-             current->pre_actions.size(), current->name.c_str());
-         if (runactions(current->pre_actions.begin(), 
-                        current->pre_actions.end(), 
-                        sess, event, event_params, is_consumed)) {
-           break;
+         
+         current = target_st;
+         
+         // execute pre-actions
+         if (current->pre_actions.size()) {
+           DBG("running %zd pre_actions of state '%s'\n",
+               current->pre_actions.size(), current->name.c_str());
+           if (runactions(current->pre_actions.begin(), 
+                          current->pre_actions.end(), 
+                          sess, active_event, active_params, is_consumed)) {
+             break;
+           }
          }
+         
+         break;
        }
+      }
+    } catch (DSMException& e) {
+      DBG("DSMException occured, type = %s\n", e.params["type"].c_str());
+      is_consumed = false;
 
-       break;
-      }
+      is_exception = true; // continue to process as exception event
+      exception_params = e.params;
+      active_params = &exception_params;
+      active_event = DSMCondition::DSMException;
     }
+
   } while (!is_consumed);
 }
 

Modified: trunk/apps/dsm/DSMStateEngine.h
===================================================================
--- trunk/apps/dsm/DSMStateEngine.h     2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/DSMStateEngine.h     2009-10-22 00:53:24 UTC (rev 1554)
@@ -73,7 +73,9 @@
     PlaylistSeparator,
     
     B2BOtherReply,
-    B2BOtherBye
+    B2BOtherBye,
+
+    DSMException
   };
 
   bool invert; 
@@ -137,6 +139,8 @@
   vector<DSMAction*> actions;
   string from_state;
   string to_state;
+
+  bool is_exception;
 };
 
 class DSMModule;
@@ -158,6 +162,19 @@
   const string& getName() { return name; }
 };
 
+class DSMException {
+ public:
+  DSMException(const string& e_type) 
+    { params["type"] = e_type; }
+
+  DSMException(map<string, string>& params)
+    : params(params) { }
+
+  ~DSMException() { }
+
+  map<string, string> params;    
+};
+
 class DSMStateEngine {
   State* current;
   DSMStateDiagram* current_diag;
@@ -189,7 +206,8 @@
 
   void runEvent(AmSession* sess,
                DSMCondition::EventType event,
-               map<string,string>* event_params);
+               map<string,string>* event_params,
+               bool run_exception = false);
 
   /** @return whether call should be accepted */
   bool onInvite(const AmSipRequest& req, DSMSession* sess);

Modified: trunk/apps/dsm/doc/Readme.dsm.txt
===================================================================
--- trunk/apps/dsm/doc/Readme.dsm.txt   2009-10-21 23:33:09 UTC (rev 1553)
+++ trunk/apps/dsm/doc/Readme.dsm.txt   2009-10-22 00:53:24 UTC (rev 1554)
@@ -26,8 +26,9 @@
 The variables may be used as parameter to most conditions and 
 actions, by prepending the variable name with a dollar sign. The
 parameters of an event (e.g. the key on key press) may be accessed
-by prepending the name with a hash. There are also 'selects' with 
-which a set of dialog properties can be accessed (e.g. @local_tag).
+by prepending the name with a hash (e.g. #key). There are also 
+'selects' with which a set of dialog properties can be accessed 
+(e.g. @local_tag).
 
 The DonkeySM can be extended by modules, which add new conditions
 and actions to the language. This way, menuing system etc can be 
@@ -37,7 +38,14 @@
 DonkeySM also has built in actions to call 
 DI methods from other modules. 
 
-It can cache a set of prompts, configured at start, in memory 
+Actions (and conditions) can throw exceptions. Once an exception occurs,
+execution of the current actions is interrupted. Exceptions are handled
+this way that special "exception" transitions are executed. Exception
+transitions are marked with "exception" in the conditions list. Once the
+FSM is in exception handling, only exception transitions are followed.
+DSMs may throw exceptions with the throw(<type>) action.
+
+DSM can cache a set of prompts, configured at start, in memory 
 using PromptCollection.
 
 A patch for fmsc 1.0.4 from the graphical FSM editor fsme 
@@ -47,6 +55,8 @@
 DI commands
 ===========
 
+DI commands allow interaction with DSM calls, and DSM script reload:
+
 postDSMEvent(string call_id, [ [[param0,val0],[param1,val1],...] ]
  post a DSM event into a call. can be used to interact with running
  calls in DSM. See DSM + monitoring + DI example in 
@@ -95,7 +105,7 @@
 the DSMStateDiagramCollection from text file and interpreted by
 the DSMChartReader, a simple stack based tokenizing compiler.
 
-DSMDialogs, which implement the DSMSession interface (additionally
+DSMCall, which implement the DSMSession interface (additionally
 to being an AmSession), run DSMStateEngine::runEvent for every event 
 that occurs that should be processed by the engine (e.g. Audio event, 
 onBye, ...). 
@@ -107,7 +117,7 @@
 get the event parameters and the session as parameters, so that they
 can operate on variables, implement selects etc. 
 
-The DSMDialog implementation is very simple, it uses a playlist and 
+The DSMCall implementation is very simple, it uses a playlist and 
 has PromptCollection to simply play prompts etc.
 
 DSMCoreModule is a 'built in' module that implements the basic 
@@ -123,9 +133,6 @@
 functionality be exposed to the DSM interpreter by custom actions and 
 conditions that interact with that specific session type.
 
-Another direction is  python/lua/... interpreter module, so that 
-conditions and actions can be expressed in a more powerful language.
-
 A set of modules exposing more of the core functionality.
 
 As the call state representation is nicely encapsulated here, this can 
@@ -171,7 +178,9 @@
 SEMS has a dynamically typed type (AmArg), why not use that one for 
 variables? That would also make DI simpler. 
  a patch is very welcome, best to semsdev list: [email protected] or 
- the tracker: http://tracker.iptel.org
+ the tracker: http://tracker.iptel.org.
+ There is also the avar array ("AmArg-Var"), which can hold AmArg 
+ variables.
 
 some performance numbers? 
  unfortunately not yet for running DSMs. DSM processing is actually fast: 

Added: trunk/apps/dsm/doc/examples/test_exception.dsm
===================================================================
--- trunk/apps/dsm/doc/examples/test_exception.dsm      2009-10-21 23:33:09 UTC 
(rev 1553)
+++ trunk/apps/dsm/doc/examples/test_exception.dsm      2009-10-22 00:53:24 UTC 
(rev 1554)
@@ -0,0 +1,10 @@
+
+initial state lobby
+  enter { 
+    playFile(wav/default_en.wav) 
+    throw(bla,blub=blu;i=somevalue); 
+  };
+transition "thrown error" lobby - exception; test(#blub=="blu"); / 
+    log(1, #i); stop(true) -> end;
+
+transition "file error" lobby - exception; test(#type="file") / stop(true) -> 
end;

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to