Commit 0066b077 by amir

initial

parent 16850be6
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
Makefile
.make.state
nbproject
build
bin
lib
tmp
CMakeFiles
CMakeCache.txt
cmake_install.cmake
install_manifest.txt
\ No newline at end of file
cmake_minimum_required(VERSION 3.6)
project(seh)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
link_directories( ../3party/lib )
include_directories(SYSTEM ../3party/rapidjson-0.11/include/rapidjson)
set(SOURCE_FILES src/seh.h src/defs/constants.h src/defs/enums.h src/defs/retstat.h src/defs/seh_types.h src/defs/seh_types.cpp src/seh/seh_engine.cpp src/seh/seh_engine.h src/seh/JsonCallFlowBuilder.cpp src/seh/JsonCallFlowBuilder.h src/seh/XMLCallFlowBuilder.cpp src/seh/XMLCallFlowBuilder.h)
add_executable(seh ${SOURCE_FILES} test/test_seh.cpp)
\ No newline at end of file
//
// Created by amir on 06/09/16.
//
#ifndef SEH_CONSTANTS_H
#define SEH_CONSTANTS_H
/**
* the projects constants
*/
namespace nsConstants
{
static const int C_NO_ENTRY = -1;
static const int C_MAX_SEH_STATE_NAME_LEN = 256;
static const int C_MAX_SEH_CALL_FLOW_FILE_NAME_LEN = 128;
static const int C_MAX_SEH_EVENT_NAME_LEN = 128;
static const int C_MAX_SEH_FULL_EVENT_NAME_LEN = 128;
static const int C_MAX_SEH_FULL_ACTION_NAME = 128;
static const int C_MAX_SEH_ERROR_MSG = 256;
static const int C_ACTION_PARAMS_LEN = 6;
static const int C_ACTION_PRIORITY_LEN = 8;
static const int C_ACTION_PRIORITY_MANDATORY_LEN = 9;
static const int C_ACTION_PRIORITY_CRITICAL_LEN = 8;
static const std::string C_ACTION_PARAMS ="Params";
static const std::string C_ACTION_PRIORITY = "Priority";
static const std::string C_ACTION_PRIORITY_MANDATORY = "Mandatory";
static const std::string C_ACTION_PRIORITY_CRITICAL = "Critical";
static const std::string C_BASE_STATE = "BaseState";
static const std::string C_NAME = "Name";
static const std::string C_NEXT_STATE = "NextState";
static const std::string C_WRONG_SEH_STATE = "Wrong State";
static const std::string C_PARAM_COND_ATTRIBUTE = "Cond";
static const std::string C_NULL_STATE = "NULL";
static const std::string C_STATES = "States";
static const std::string C_EVENTS = "Events";
static const std::string C_ACTIONS = "Actions";
static const std::string C_TYPE = "Type";
static const std::string C_IF_THEN = "Then";
static const std::string C_IF_ELSE = "Else";
static const std::string C_CASES = "Cases";
}
#endif //SEH_CONSTANTS_H
//
// Created by amir on 06/09/16.
//
#ifndef SEH_ENUMS_H
#define SEH_ENUMS_H
namespace nsEnums
{
enum eRetStat
{
eFail,
eSuccess
};
enum eEventActionType
{
eActionType_Regular,
eActionType_If,
eActionType_While,
eActionType_Switch
};
}
#endif //SEH_ENUMS_H
//
// Created by amir on 06/09/16.
//
#ifndef SEH_RETSTAT_H
#define SEH_RETSTAT_H
#include <string>
#include "enums.h"
using namespace nsEnums;
class RetStat
{
private:
eRetStat retstat_;
int ret_code_;
std::string error_text_;
public:
RetStat(): retstat_(eSuccess), ret_code_(0) {}
RetStat(bool success_, int ret_code_, const std::string &error_text_) : retstat_(eSuccess),
ret_code_(ret_code_),
error_text_(error_text_) {}
void Reset()
{
retstat_ = eSuccess;
ret_code_ = 0;
error_text_.clear();
}
void SetSuccess() { retstat_ = eSuccess; }
void SetFail() { retstat_ = eFail; }
void SetFail(std::string &error)
{
retstat_ = eFail;
error_text_.assign(error);
}
void SetFail(const char* error)
{
retstat_ = eFail;
error_text_.assign(error);
}
bool Success() { return (retstat_ == eSuccess); }
bool Fail() { return (retstat_ == eFail); }
std::string& GetError() { return error_text_; }
int GetRetCode() const {
return ret_code_;
}
};
#endif //SEH_RETSTAT_H
//
// Created by amir on 06/09/16.
//
#include "retstat.h"
#include "seh_types.h"
RetStat ComplexEventAction::ActivateActions(EventData& eventData,
ActivateActionData& activateActionData,
bool bMoveToNextState)
{
int iNumOfActions = eventData.getNumOfActions();
for (EventAction eventAction : eventData.actions)
{
/*
* activating the action
*/
retStat = (RetStat) eventAction.ActivateAction(activateActionData); //action.invoke(activateActionData.object, eventAction.param);
if (retStat.Fail())
{
//logger.severe("ComplexEventAction::ActivateActions-\tFailed in Action");
SEH_LOG_ERROR("ComplexEventAction::ActivateActions-\tFailed in Action: ",retStat.GetError());
break;
}
}
/******************************************
* check whether to move to the next state
******************************************/
if (bMoveToNextState)
{
if (iNumOfActions > 0) {
if (eventData.NextStateValid()) {
activateActionData.boolWasStateChanged = true;
activateActionData.nextStateIndex.uiStateFlowIndex = eventData.nextState.stateIndex.uiStateFlowIndex;
activateActionData.nextStateIndex.uiStateIndex = eventData.nextState.stateIndex.uiStateIndex;
//logger.info("SEHEngine-\tChanging to State: " + eventData.nextState.stateName);
SEH_LOG("ComplexEventAction::ActivateActions\tChanging to State: ",eventData.nextState.stateName);
} else {
activateActionData.boolWasStateChanged = false;
}
} else {
retStat.SetFail();
return retStat;
}
}
retStat.SetSuccess();
return retStat;
}
void EventIfAction::Reset()
{
EventAction::Reset();
trueActions.Reset();
falseActions.Reset();
}
RetStat EventIfAction::ActivateAction(ActivateActionData& activateActionData)
{
retStat.Reset();
/***********************************
* Activating the Condition action
**********************************/
retStat = EventAction::ActivateAction(activateActionData);
if (retStat.Success())
return ActivateActions(trueActions, activateActionData, true);
else
return ActivateActions(falseActions, activateActionData, true);
}
void EventWhileAction::Reset()
{
EventAction::Reset();
whileActions.Reset();
}
RetStat EventWhileAction::ActivateAction(ActivateActionData &activateActionData)
{
retStat.Reset();
while (EventAction::ActivateAction(activateActionData).Success()) {
retStat = ActivateActions(whileActions, activateActionData, true);
if (retStat.Fail())
return retStat;
}
/******************************************
* check whether to move to the next state
******************************************/
if (whileActions.NextStateValid() )
{
activateActionData.boolWasStateChanged = true;
activateActionData.nextStateIndex = whileActions.nextState.stateIndex;
SEH_LOG("EventWhileAction-\tChanging to State: ",whileActions.nextState.stateName);
}
else
{
activateActionData.boolWasStateChanged = false;
}
return retStat;
}
void EventSwitchAction::Reset() {
switchActions.clear();
}
RetStat EventSwitchAction::ActivateAction(ActivateActionData &activateActionData) {
retStat.Reset();
retStat = EventAction::ActivateAction(activateActionData);
if (retStat.Fail())
return retStat;
/************************************************************
* Activating the appropriate case according to the ret_code
***********************************************************/
if (retStat.GetRetCode() < switchActions.size())
{
EventData eventData = switchActions[retStat.GetRetCode()];
retStat = ActivateActions(eventData,activateActionData,true);
if(retStat.Success())
{
/******************************************
* check whether to move to the next state
******************************************/
if (eventData.NextStateValid() )
{
activateActionData.boolWasStateChanged = true;
activateActionData.nextStateIndex = eventData.nextState.stateIndex;
SEH_LOG("EventSwitchAction-\tChanging to State: ",eventData.nextState.stateName);
}
else
{
activateActionData.boolWasStateChanged = false;
}
}
}
else
{
retStat.SetFail("EventSwitchAction::ActivateAction-\tReturn value is bigger the num of switch cases");
SEH_LOG_ERROR(retStat.GetError());
return retStat;
}
return retStat;
}
void ActivateActionData::Reset() {
this->boolWasStateChanged = false;
this->nextStateIndex.Reset();
}
//
// Created by amir on 06/09/16.
//
#ifndef SEH_SEH_TYPES_H
#define SEH_SEH_TYPES_H
#include <functional>
#include <vector>
#include <iostream>
#include <map>
#include "constants.h"
#include "retstat.h"
template <typename Arg, typename... Args>
void seh_log(std::ostream& out, Arg&& arg, Args&&... args)
{
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander{0, (void(out << ',' << std::forward<Args>(args)),0)...};
}
#define SEH_LOG(...) seh_log(std::cout,__VA_ARGS__)
#define SEH_LOG_ERROR(...) seh_log(std::cerr,__VA_ARGS__) // << ... << ... << std::endl
#define SEH_METHOD_ERROR(...) SEH_LOG_ERROR(__PRETTY_FUNCTION__,__VA_ARGS__)
#define SEH_METHOD_LOG(...) SEH_LOG(__PRETTY_FUNCTION__,__VA_ARGS__)
using namespace std;
struct StateIndex
{
int uiStateIndex;
int uiStateFlowIndex;
StateIndex()
{
}
StateIndex(int uiStateIndex,int uiFlowIndex)
{
this->uiStateIndex = uiStateIndex;
this->uiStateFlowIndex = uiFlowIndex;
}
void Reset()
{
uiStateIndex = nsConstants::C_NO_ENTRY;
uiStateFlowIndex = nsConstants::C_NO_ENTRY;
}
bool isValid()
{
return (uiStateIndex != nsConstants::C_NO_ENTRY &&
uiStateFlowIndex != nsConstants::C_NO_ENTRY);
}
};
struct ISEHParam
{
virtual void SetParam(const char* name, const char* value) = 0;
};
/**
* this is the interface of all the classes
* that use the GenericSEH engine
* @author amir
*
*/
typedef std::function<RetStat (ISEHParam* )> AFP;
struct IBaseSEH
{
virtual AFP resolveAction(const char* actionName) = 0;
virtual int resolveEvent(const char* eventName);
virtual const char* resolveEventName(int event);
virtual ISEHParam* getNewSEHParam();
virtual void setAppData(void* p_appData);
//public RetStatSupplier invokeFunc(CallSite callSite, SEHParam sehParam) throws Throwable;
};
/**
* Data needed to activate the actions and move to the next state
*/
struct ActivateActionData
{
//IBaseSEH* p_object;
StateIndex nextStateIndex;
bool boolWasStateChanged; // if true means that the called object
// change the state - moved to the next
// state
void Reset();
};
/**
* contains the data for the action such as the Method (function pointer),
* the param to pass to the method is this a mandatory action or critical.
* This is also a base class for other complex actions
*
* @author amir
*
*/
struct EventAction
{
string name;
//RetStatSupplier actionFunc;
AFP action;
ISEHParam* p_param_;
eEventActionType actionType;
bool bIsMandatory = false; // mandatory means that it have to be
// execute , even if the former action
// failed
bool bIsCritical = false; // Critical means that if this action
// failes then none of the following
// actions should be
// executed, unless they have 'mandatory' attribute
EventAction()
{
actionType = eActionType_Regular;
}
void Reset()
{
name.clear();
action = nullptr;
p_param_ = nullptr;
bIsMandatory = false;
bIsCritical = false;
}
EventAction& operator = (const EventAction& eventAction)
{
this->name.assign(eventAction.name);
this->action = eventAction.action;
if (eventAction.p_param_ != nullptr)
{
this->p_param_ = eventAction.p_param_;
}
return *this;
}
eEventActionType getActionType()
{
return actionType;
}
/**
* activating the action
*
* @param activateActionData
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
virtual RetStat ActivateAction(ActivateActionData& activateActionData)
{
activateActionData.boolWasStateChanged = false;
if (this->action != nullptr)
return this->action(p_param_);
// else // backward support for xml callflow builder
// return (RetStat) this.action.invoke(activateActionData.object, param);
}
bool isActionMandatory() { return bIsMandatory; }
bool isActionCritical() { return bIsCritical; }
};
/**
* data for the next state
*
* @author amir
*
*/
struct NextState
{
StateIndex stateIndex;
string stateName;
void Reset()
{
stateIndex.Reset();
stateName.clear();
}
NextState& operator = (const NextState& nextState)
{
this->stateIndex = nextState.stateIndex;
this->stateName.assign(nextState.stateName);
return *this;
}
bool IsValid() { return !stateName.empty(); }
string& getStateName() { return stateName; }
void setStateName(string& stateName) {
this->stateName.assign(stateName);
}
void setStateName(char* stateName) {
this->stateName.assign(stateName);
}
};
/**
* Contains the event data: the list of actions to activate, the next state
* and the event name
*
* @author amir
*
*/
struct EventData
{
// vector < tEventAction*> ta_Actions;
// test - amir
vector<EventAction> actions;
NextState nextState;
string eventName;
void Reset()
{
actions.clear();
nextState.Reset();
eventName.clear();
}
int getNumOfActions()
{
return actions.size();
}
EventData& operator = (const EventData& eventData)
{
if (!eventData.actions.empty())
this->actions = eventData.actions;
this->nextState = eventData.nextState;
this->eventName.assign(eventData.eventName);
return *this;
}
void AddAction(EventAction& action)
{
actions.push_back(action);
}
bool Empty() { return actions.empty(); }
bool NextStateValid() { return nextState.IsValid(); }
};
/**
* contains basic handling for activating complex actions
*
* @author amir
*
*/
struct ComplexEventAction: public EventAction
{
RetStat retStat;
ComplexEventAction(): EventAction()
{
}
RetStat ActivateActions(EventData& eventData,
ActivateActionData& activateActionData,
bool bMoveToNextState);
};
struct EventIfAction: public ComplexEventAction
{
EventData trueActions;
EventData falseActions;
EventIfAction() { this->actionType = eActionType_If; }
void Reset();
RetStat ActivateAction(ActivateActionData& activateActionData);
EventIfAction& operator = (const EventIfAction& eventIfAction)
{
this->operator=(eventIfAction);
trueActions = eventIfAction.trueActions;
falseActions = eventIfAction.falseActions;
return *this;
}
};
struct EventWhileAction: public ComplexEventAction
{
EventData whileActions;
EventWhileAction() { this->actionType = eActionType_While; }
void Reset();
RetStat ActivateAction(ActivateActionData& activateActionData);
EventWhileAction& operator = (const EventWhileAction& eventAction)
{
this->operator=(eventAction);
whileActions = eventAction.whileActions;
return *this;
}
};
struct EventSwitchAction: public ComplexEventAction
{
vector<EventData> switchActions;
//short numOfCases;
EventSwitchAction() { this->actionType = eActionType_Switch; }
void Reset();
RetStat ActivateAction(ActivateActionData& activateActionData);
EventSwitchAction& operator = (const EventSwitchAction& eventSwitchAction)
{
this->operator=(eventSwitchAction);
// numOfCases = eventSwitchAction.numOfCases;
switchActions = eventSwitchAction.switchActions;
return *this;
}
};
struct State
{
map<string,EventData> eventsMap;
string stateName;
NextState baseState; // the base state for this state (optional)
State()
{
Reset();
}
void Reset()
{
eventsMap.clear();
stateName.clear();
baseState.Reset();
}
};
struct CallFlow
{
int flowIndex = 0;
vector<State> stateArray;
int iNumOfStates;
string flowFileName;
IBaseSEH* p_baseSEHObject;
void Reset()
{
flowIndex = 0;
stateArray.clear();
flowFileName.clear();
iNumOfStates = 0;
p_baseSEHObject = nullptr;
}
string& GetFlowFileNameStr()
{
return flowFileName;
}
const char* GetFlowFileName()
{
return flowFileName.c_str();
}
};
struct ICallFlowBuilder {
virtual RetStat BuildFlowTableFromFile(string& flowFileName, CallFlow *p_callFlow, IBaseSEH *p_baseSEHObject) = 0;
virtual RetStat BuildFlowTableFromString(string& flowFSM, CallFlow* p_callFlow, IBaseSEH *baseSEHObject) = 0;
};
#endif //SEH_SEH_TYPES_H
//
// Created by amir on 04/09/16.
//
#ifndef SEH_SEH_H
#define SEH_SEH_H
#include <seh_types.h>
#include <cstddef>
using namespace std;
struct tGeneral_StateIndexes
{
UINT ui_StateIndex;
UINT ui_StateFlowIndex;
void Reset()
{
ui_StateIndex = NO_ENTRY;
ui_StateFlowIndex = NO_ENTRY;
}
};
const int MAX_SEH_STATE_NAME_LEN = 256;
const int MAX_SEH_CALL_FLOW_FILE_NAME_LEN = 128;
const int MAX_SEH_EVENT_NAME_LEN = 128;
const int MAX_SEH_FULL_EVENT_NAME_LEN = 128;
const int MAX_SEH_FULL_ACTION_NAME = 128;
const int MAX_SEH_ERROR_MSG = 256;
#define ACTION_TYPE_REGULAR "Action"
#define ACTION_TYPE_COND_IF "If"
#define ACTION_TYPE_COND_WHILE "While"
#define ACTION_TYPE_COND_SWITCH "Switch"
#define ACTION_PARAMS "Params"
#define ACTION_PARAMS_LEN 6
#define ACTION_PRIORITY "Priority"
#define ACTION_PRIORITY_LEN 8
#define ACTION_PRIORITY_MANDATORY "Mandatory"
#define ACTION_PRIORITY_MANDATORY_LEN 9
#define ACTION_PRIORITY_CRITICAL "Critical"
#define ACTION_PRIORITY_CRITICAL_LEN 8
#define BASE_STATE "BaseState"
#define WRONG_SEH_STATE "Wrong State"
const int BASE_STATE_LEN = 9;
#define NULL_STATE "NULL"
const int NULL_STATE_LEN = 4;
// test
const int MAX_SEH_ACTIONS = 32;
template <typename T,typename P,UINT MAX_EVENTS,UINT MAX_PARTIES>
class General_StateEventHandler
{
public:
/******************************
* Definitions & Structs
******************************/
typedef eRetStat (T::*AFP)(P* pt_Param); // action pointer - return SUCCESS / FAIL
typedef tRetStat (T::*VAFP)(P* pt_Param); // value action pointer - return code and SUCCESS/FAIL
typedef AFP (T::*RAP)(char* ba_ActionName); // ResolveAction pointer
typedef VAFP (T::*RVAP)(char* ba_ActionName); // Resolve value Action pointer
typedef UINT (T::*REP)(char* ba_EventName); // ResolveEvent pointer
typedef UINT (T::*RPP)(char* ba_PartyName); // ResolveParty pointer
typedef const char* (T::*RENP)(UINT ui_Event); // ResolveEventName pointer
typedef t_XmlItemTree* (T::*PFFP)(char* ba_FlowFileName); // Parse flow file pointer
typedef P* (T::*GNPFP)(); // get new SEH p_param_ pointer
struct tActivateActionData
{
T* pt_Object;
tGeneral_StateIndexes* pt_NextStateIndex;
bool* pb_WasStateChanged; // if true means that the called object change the state - moved to the next state
};
enum eEventActionType
{
eActionType_Regular,
eActionType_If,
eActionType_While,
eActionType_Switch
};
struct tEventAction
{
AFP t_Action;
int i_Party; // 0 - no party, 1 - A, 2 - B ....
P* pt_Param;
eEventActionType e_Type;
bool b_IsMandatory; // mandatory means that it have to be execute , even if the former action failed
bool b_IsCritical; // Critical means that if this action failes then none of the following actions should be
// executed, unless they have 'mandatory' attribute
tEventAction() { e_Type = eActionType_Regular; }
virtual void Reset()
{
t_Action = NULL;
pt_Param = NULL;
b_IsMandatory = false;
b_IsCritical = false;
}
tEventAction& operator = (const tEventAction& t_EventAction)
{
t_Action = t_EventAction.t_Action;
if (t_EventAction.pt_Param)
{
pt_Param = new P;
*pt_Param = *t_EventAction.pt_Param;
}
return *this;
}
eEventActionType GetActionType() { return e_Type; }
virtual eRetStat ActivateAction(tActivateActionData* pt_ActivateActionData)
{
*(pt_ActivateActionData->pb_WasStateChanged) = false;
return (pt_ActivateActionData->pt_Object->*(t_Action))(pt_Param);
}
bool IsActionMandatory() { return b_IsMandatory; }
bool IsActionCritical() { return b_IsCritical; }
};
struct tValueEventAction: public tEventAction
{
VAFP t_VAction;
void Reset()
{
t_VAction = NULL;
tEventAction::Reset();
}
tValueEventAction& operator = (const tValueEventAction& t_EventAction)
{
t_VAction = t_EventAction.t_VAction;
tEventAction::operator = (t_EventAction);
return *this;
}
};
struct tNextState
{
tGeneral_StateIndexes t_StateIndex;
char ba_StateName[MAX_SEH_STATE_NAME_LEN];
void Reset()
{
t_StateIndex.Reset();
ba_StateName[0] = NULL;
}
tNextState& operator = (const tNextState& t_NextState)
{
t_StateIndex = t_NextState.t_StateIndex;
strcpy(ba_StateName,t_NextState.ba_StateName);
return *this;
}
bool IsValid() { return (ba_StateName[0] != '\0'); }
};
typedef tEventAction* tEventActionPtr;
struct tEventData
{
// vector < tEventAction*> ta_Actions;
// test - amir
tEventAction* ta_Actions[MAX_SEH_ACTIONS];
short s_NumOfActions; // max
tNextState t_NextState;
char ba_EventName[MAX_SEH_FULL_EVENT_NAME_LEN];
void Reset()
{
s_NumOfActions = 0;
t_NextState.Reset();
ba_EventName[0] = NULL;
}
tEventData& operator = (const tEventData& t_EventData)
{
if (t_EventData.s_NumOfActions > 0)
memcpy(ta_Actions,t_EventData.ta_Actions,(t_EventData.s_NumOfActions * sizeof(tEventAction*)));
s_NumOfActions = t_EventData.s_NumOfActions;
t_NextState = t_EventData.t_NextState;
strcpy(ba_EventName,t_EventData.ba_EventName);
return *this;
}
eRetStat AddAction(tEventAction* pt_Action) {
if (s_NumOfActions < MAX_SEH_ACTIONS)
{
ta_Actions[s_NumOfActions++] = pt_Action;
return SUCCESS;
}
else
return FAIL;
}
bool IsEmpty() { return (s_NumOfActions == 0); /*ta_Actions.empty(); */}
bool IsNextStateValid() { return t_NextState.ba_StateName[0] != '\0'; }
};
struct tComplexEventAction: public tEventAction
{
tEventAction* pt_EventAction;
eRetStat ActivateActions(tEventData* pt_EventData,
tActivateActionData* pt_ActivateActionData,
bool b_MoveToNextState);
};
struct tComplexValueEventAction: public tValueEventAction
{
tValueEventAction* pt_EventAction;
eRetStat ActivateActions(tEventData* pt_EventData,
tActivateActionData* pt_ActivateActionData,
bool b_MoveToNextState);
};
struct tEventIfAction: public tComplexEventAction
{
tEventData t_TrueActions;
tEventData t_FalseActions;
tEventIfAction() { this->e_Type = eActionType_If; }
void Reset();
eRetStat ActivateAction(tActivateActionData* pt_ActivateActionData);
tEventIfAction& operator = (const tEventIfAction& t_EventAction)
{
tEventAction::oprator = (t_EventAction);
t_TrueActions = t_EventAction.t_TrueActions;
t_FalseActions = t_EventAction.t_FalseActions;
return *this;
}
};
struct tEventWhileAction: public tComplexEventAction
{
tEventData t_WhileActions;
tEventWhileAction() { this->e_Type = eActionType_While; }
void Reset();
eRetStat ActivateAction(tActivateActionData* pt_ActivateActionData);
tEventWhileAction& operator = (const tEventWhileAction& t_EventAction)
{
tEventAction::oprator = (t_EventAction);
t_WhileActions = t_EventAction.t_WhileActions;
return *this;
}
};
struct tEventSwitchAction: public tComplexValueEventAction
{
tEventData* pt_SwitchActions;
short s_NumOfCases;
tEventSwitchAction() { this->e_Type = eActionType_Switch; }
void Reset();
eRetStat ActivateAction(tActivateActionData* pt_ActivateActionData);
tEventSwitchAction& operator = (const tEventSwitchAction& t_EventAction)
{
tValueEventAction::operator = (t_EventAction);
s_NumOfCases = t_EventAction.s_NumOfCases;
pt_SwitchActions = new tEventData[s_NumOfCases];
for (short s_i = 0; s_i < s_NumOfCases; s_i++)
pt_SwitchActions[s_i] = t_EventAction.pt_SwitchActions[s_i];
return *this;
}
};
typedef struct
{
tEventData taa_EventCellsArray[MAX_EVENTS][MAX_PARTIES];
char ba_StateName[MAX_SEH_STATE_NAME_LEN];
tNextState t_BaseState; // the base state for this state (optional)
void Reset()
{
for (int i_x = 0; i_x < MAX_EVENTS; i_x++)
for (int i_y = 0; i_y < MAX_PARTIES; i_y++)
taa_EventCellsArray[i_x][i_y].Reset();
ba_StateName[0] = NULL;
t_BaseState.Reset();
}
}tState;
typedef struct
{
tState* pta_StateArray;
int i_NumOfStates;
char ba_FlowFileName[MAX_SEH_CALL_FLOW_FILE_NAME_LEN];
void Reset()
{
pta_StateArray = NULL;
ba_FlowFileName[0] = NULL;
i_NumOfStates = 0;
}
char* GetFlowFileName() { return ba_FlowFileName; }
}tCallFlow;
private:
/**********************
* Members
**********************/
char mba_FlowsFileName[MAX_SEH_CALL_FLOW_FILE_NAME_LEN];
tCallFlow* mpta_CallFlowArray;
UINT mui_CurrentNumOfCallFlows;
UINT mui_MaxNumberOfCallFlows;
UINT mui_StartChildCallFlows;
tState* mpt_CurrentFirstState;
tEventAction mt_EventAction;
tEventData mt_EventData;
tGeneral_StateIndexes* mpt_StateIndex;
tState* mpt_State;
tEventData* mpt_EventData;
tActivateActionData* mpt_ActivateActionData;
t_XmlItemTree* mpt_XmlTree;
char mba_ErrorMsg[MAX_SEH_ERROR_MSG];
UINT mui_CurrentFlowNumOfStates;
char mba_ActionName[MAX_SEH_FULL_ACTION_NAME];
char mba_EventName[MAX_SEH_FULL_EVENT_NAME_LEN];
T* mpt_Object;
AFP mt_ActionFunc;
RAP mt_ResolveActionFunc;
RVAP mt_ResolveValueActionFunc;
REP mt_ResolveEventFunc;
RPP mt_ResolvePartyFunc;
RENP mt_ResolveEventNameFunc;
PFFP mt_ParseFlowFileFunc;
GNPFP mt_GetNewSEHParamFunc;
UINT mui_DefaultParty; // default Party index when no party stated
map<string,tGeneral_StateIndexes> mc_StateIndexMap;
map<string,tGeneral_StateIndexes>::iterator mt_StateIterator;
protected:
tEventAction* mpt_EventAction;
/************************
* Methods
***********************/
void Reset();
eRetStat InitMembers();
eRetStat BuildCallFlowTables(); // Reading the file that contains the list of the call-flows file names
eRetStat BuildFlowTable(int i_FlowIndex,
char* ba_FlowFileName); // building the tables for a single call-flow
eRetStat GetState(t_ItemNode* pt_Node,tState* pt_State);
eRetStat GetEvent(t_ItemNode* pt_Node);
eRetStat GetEventActions(t_ItemNode* pt_Node);
eRetStat GetAction(t_ItemNode* pt_Node);
eRetStat GetActionParams(tEventAction* pt_Action,t_ItemNode* pt_Node);
// Child/Parent handling
eRetStat GetParentState(char* ba_StateName,tState** ppt_ParentState);
eRetStat GetParentEvent(tState* pt_ParentState,char* ba_EventName,tEventData** ppt_ParentEvent);
// Special handling
eRetStat HandleEventIfAction(tEventIfAction* pt_Action,t_ItemNode* pt_Node);
eRetStat HandleEventWhileAction(tEventWhileAction* pt_Action,t_ItemNode* pt_Node);
eRetStat HandleEventSwitchAction(tEventSwitchAction* pt_Action,t_ItemNode* pt_Node);
eRetStat GetEventData(tEventData* pt_EventData,t_ItemNode* pt_Node);
// Resolving
UINT ResolveFlowName(char* ba_FlowName);
UINT ResolveFlowPrefix(char* ba_FlowPrefix);
UINT ResolveParty(char* ba_PartyName);
UINT ResolveEventEnum(char* ba_EventName);
eRetStat ResolveNextStateIndex(tNextState* pt_NextState);
eRetStat ResolveNextStateIndexes(UINT ui_StartFlow = 0);
eRetStat ResolveAction(tEventAction* pt_Action,char* ba_Action,bool b_ValueAction = false);
eRetStat ResolveSimpleAction(tEventAction* pt_Action,t_ItemNode* pt_Node,bool b_ValueAction = false);
eRetStat ResolveActionWithParams(tEventAction* pt_Action,t_ItemNode* pt_Node,bool b_ValueAction = false);
eRetStat ResolveComplexActionNextState(tEventAction* pt_Action);
eRetStat ReplaceParentStates(UINT ui_FlowIndex);
eRetStat ActivateActions(tGeneral_StateIndexes* pt_NextStateIndex);
eRetStat ActivateAction();
void AddStateToMap(char* pba_StateName,tGeneral_StateIndexes* pt_StateIndex);
public:
General_StateEventHandler();
eRetStat Init(const char* ba_FlowsFileName,
UINT ui_MaxNumOfCallFlows,
T* pt_Object,
RAP t_ResolveActionFunc,
REP t_ResolveEventFunc,
RPP t_ResolvePartyFunc,
PFFP t_ParseFlowFileFunc,
UINT ui_DefaultParty,
RENP t_ResolveEventNameFunc = NULL,
RVAP t_ResolveValueActionFunc = NULL);
eRetStat InitChild(const char* ba_ChildFlowsFileName,
GNPFP t_GetNewSEHParamFunc);
eRetStat AddChildFlow(const char* ba_CallFlowFileName,
GNPFP t_GetNewSEHParamFunc);
eRetStat AddCallFlow(char* ba_CallFlowFileName);
eRetStat HandleEvent(tGeneral_StateIndexes* pt_StateIndex,UINT ui_Event,UINT ui_Party);
const char* GetStateName(tGeneral_StateIndexes* pt_StateIndex);
tCallFlow* GetCallFlowsIface() { return mpta_CallFlowArray; }
UINT GetCurrentNumOfCallFlows() { return mui_CurrentNumOfCallFlows; }
eRetStat GetStateIndex(tGeneral_StateIndexes* pt_StateIndex,
const char* ba_FlowFileName,
const char* ba_StateName);
eRetStat GetStateIndex(tGeneral_StateIndexes* pt_StateIndex,
const char* ba_StateName);
};
#endif //SEH_SEH_H
//
// Created by amir on 07/09/16.
//
#include "JsonCallFlowBuilder.h"
#include <document.h>
#include <fstream>
#include <sstream>
RetStat JsonCallFlowBuilder::BuildFlowTableFromFile(string& flowFileName, CallFlow *p_callFlow,
IBaseSEH *p_baseSEHObject) {
RetStat retStat;
int iCurrentState = 0;
this->p_callFlow_ = p_callFlow;
this->p_baseSEHObject_ = p_baseSEHObject;
this->flowFileName_.assign(flowFileName);
//defaultSEHParam = this.baseSEHObject.getNewSEHParam();
/*********************************************
* copying the file name and reading the file
********************************************/
this->p_callFlow_->flowFileName.assign(flowFileName);
std::ifstream jsonFile(flowFileName);
if(jsonFile.is_open())
{
std::stringstream buffer;
buffer << jsonFile.rdbuf();
p_flowDoc_ = new Document();
if (!p_flowDoc_->Parse<0>(buffer.str().c_str()).HasParseError())
{
retStat = CreateCallFlow(flowFileName, iCurrentState);
} else
{
retStat.SetFail(string("Failed to parse File: ").append(flowFileName));
}
}
else
{
retStat.SetFail(string("Failed to open File: ").append(flowFileName));
}
return retStat;
}
RetStat JsonCallFlowBuilder::BuildFlowTableFromString(string& flowFSM, CallFlow* p_callFlow, IBaseSEH *p_baseSEHObject) {
RetStat retStat;
int iCurrentState = 0;
this->p_callFlow_ = p_callFlow;
this->p_baseSEHObject_ = p_baseSEHObject;
//this->flowFileName_.assign(flowFileName);
//defaultSEHParam = this.baseSEHObject.getNewSEHParam();
/*********************************************
* copying the file name and reading the file
********************************************/
//this->p_callFlow_->flowFileName.assign(flowFileName);
p_flowDoc_ = new Document();
if (!p_flowDoc_->Parse<0>(flowFSM.c_str()).HasParseError())
{
retStat = CreateCallFlow(this->flowFileName_, iCurrentState);
} else
{
retStat.SetFail(string("Failed to parse flow string").append(""));
}
return retStat;
}
JsonCallFlowBuilder::JsonCallFlowBuilder() {
this->eventAction_.Reset();
this->eventData_.Reset();
this->flowFileName_.clear();
}
RetStat JsonCallFlowBuilder::CreateCallFlow(string& flowFileName, int iCurrentState) {
RetStat retStat;
State* p_state;
Document& flowDoc = *p_flowDoc_;
//JsonNode currentStateNodePtr;
/*************************************************
* Going over the tree: - Counting the number of states - Allocating
* the states - going over each state and reading it's data
************************************************/
const Value& statesArrayNode = flowDoc[nsConstants::C_STATES.c_str()];
/************************************
* - Counting the number of states and setting the node to the first
* child
*************************************/
if (statesArrayNode.IsArray() )
p_callFlow_->iNumOfStates = statesArrayNode.Size();
/***************************
* - Allocating the states
***************************/
if (p_callFlow_->iNumOfStates > 0)
{
//p_callFlow_->stateArray = new State[p_callFlow_->iNumOfStates];
/*
* allocating each cell
*/
// for (int i = 0; i < p_callFlow_->iNumOfStates; i++)
// p_callFlow_->stateArray[i] = new State();
/*************************************
* Going over the States and Setting the State Names
************************************/
for (Value::ConstValueIterator itr = statesArrayNode.Begin(); itr != statesArrayNode.End(); ++itr)
{
Document* p_currentStateNode = (Document*)itr; //stateNode;
State state;
p_state = &state;//p_callFlow_->stateArray[iCurrentState];
//p_currentStateNode = stateNode;
/*
* Getting the <Name> tag - first child
*/
p_state->stateName = (*p_currentStateNode)[nsConstants::C_NAME.c_str()].GetString();//.asText();
/*
* Getting the State data
*/
retStat = GetState(*p_currentStateNode, p_state );
if (retStat.Success())
{
/****************************
* Going to the next state
****************************/
iCurrentState++;
}
else
{
if (retStat.GetError().empty())
retStat.SetFail(string("JsonCallFlowBuilder.BuildFlowTable-\tFailed in State: ").append(p_state->stateName));
break;
}
/*********************
* pushing the state
*******************/
p_callFlow_->stateArray.push_back(state);
}
}
else
{
retStat.SetFail(string("JsonCallFlowBuilder.BuildFlowTable-\tno States for ").append(flowFileName));
}
return retStat;
}
RetStat JsonCallFlowBuilder::GetState(Document &stateNode, State *p_State) {
RetStat retStat;
/***************************
* Getting the State Events
**************************/
/*
* checking for BaseState tags
*/
auto& baseStateNode = stateNode[nsConstants::C_BASE_STATE.c_str()];
if (baseStateNode.IsString())
{
p_State->baseState.Reset();
// Getting the base state name
p_State->baseState.stateName = baseStateNode.GetString();
}
auto& eventsArray = stateNode[nsConstants::C_EVENTS.c_str()];
if (eventsArray.IsArray())
{
for (auto eventNodePtr = eventsArray.Begin(); eventNodePtr != eventsArray.End(); ++eventNodePtr)
{
Document& eventNode = *(Document*)eventNodePtr;
/****************************
* Getting the Event
****************************/
retStat = GetEvent(eventNode );
if (retStat.Fail())
{
if (retStat.GetError().empty())
retStat.SetFail("JsonCallFlowBuilder.GetState-\tFailed Getting the event");
return retStat;
}
/*
* adding the event to map
*/
EventData eventData = this->eventData_;
p_State->eventsMap[this->eventData_.eventName] = eventData;
}
}
else
{
retStat.SetFail(string("JsonCallFlowBuilder.GetState-\tno events node for state: ")
.append(stateNode[nsConstants::C_NAME.c_str()].GetString())
.append(", file: ").append(this->flowFileName_));
}
return retStat;
}
RetStat JsonCallFlowBuilder::GetEvent(Document &eventNode) {
return RetStat();
}
//
// Created by amir on 07/09/16.
//
#ifndef SEH_JSONCALLFLOWBUILDER_H
#define SEH_JSONCALLFLOWBUILDER_H
#include <document.h>
#include "../defs/seh_types.h"
using namespace std;
using namespace rapidjson;
class JsonCallFlowBuilder : public ICallFlowBuilder {
private:
EventData eventData_;
EventAction eventAction_;
EventAction* p_eventAction_;
CallFlow* p_callFlow_;
IBaseSEH* p_baseSEHObject_;
string flowFileName_;
Document* p_flowDoc_;
public:
JsonCallFlowBuilder();
virtual RetStat BuildFlowTableFromFile(string& flowFileName, CallFlow *p_callFlow, IBaseSEH *p_baseSEHObject) override;
virtual RetStat BuildFlowTableFromString(string& flowFSM, CallFlow* p_callFlow, IBaseSEH *baseSEHObject) override;
RetStat CreateCallFlow(string &basic_string, int iCurrentState);
RetStat GetState(Document &stateNode, State *p_State);
RetStat GetEvent(Document &eventNode);
};
#endif //SEH_JSONCALLFLOWBUILDER_H
//
// Created by amir on 07/09/16.
//
#include "XMLCallFlowBuilder.h"
RetStat XMLCallFlowBuilder::BuildFlowTableFromFile(string& flowFileName, CallFlow *p_callFlow, IBaseSEH *p_baseSEHObject) {
return RetStat();
}
RetStat XMLCallFlowBuilder::BuildFlowTableFromString(string& flowFSM, CallFlow* p_callFlow, IBaseSEH *baseSEHObject) {
return RetStat();
}
//
// Created by amir on 07/09/16.
//
#ifndef SEH_XMLCALLFLOWBUILDER_H
#define SEH_XMLCALLFLOWBUILDER_H
#include "../defs/seh_types.h"
class XMLCallFlowBuilder : public ICallFlowBuilder{
public:
virtual RetStat BuildFlowTableFromFile(string& flowFileName, CallFlow *p_callFlow, IBaseSEH *p_baseSEHObject) override;
virtual RetStat BuildFlowTableFromString(string& flowFSM, CallFlow* p_callFlow, IBaseSEH *baseSEHObject) override;
};
#endif //SEH_XMLCALLFLOWBUILDER_H
//
// Created by amir on 07/09/16.
//
#include <fstream>
#include <sstream>
#include "seh_engine.h"
#include "JsonCallFlowBuilder.h"
#include "XMLCallFlowBuilder.h"
template <typename _Map, typename _Key>
void* GetFromMap(_Map& map, _Key& key) {
void * p_val = nullptr;
auto iter = map.find(key);
if (iter != map.end())
p_val = &iter->second;
return p_val;
}
void SehEngine::Reset() {
flowsFileName_.clear();
currentCallFlowIndex = nsConstants::C_NO_ENTRY;
maxNumberOfCallFlows_ = 0;
startChildCallFlows = 0;
callFlowArray_.clear();
stateIndexMap_.clear();
}
void SehEngine::InitMembers() {
callFlowMap_.clear();
flowFilesMap_.clear();
activateActionData_.Reset();
//activateActionDat_a.object = baseSEHObject;
eventAction_.Reset();
}
RetStat SehEngine::BuildMultiCallFlowTables(map<string, string> &flowFilesMap) {
RetStat retStat;
/*
* go over the flows and parse them
*/
for (auto entry : flowFilesMap)
{
auto baseSehObjIterator = baseSEHObjectMap_.find(entry.first);
if (baseSehObjIterator != baseSEHObjectMap_.end())
{
p_baseSEHObject_ = baseSehObjIterator->second;
retStat = BuildSingleFlowTable(entry.first, entry.second);
if (retStat.Fail())
{
if (!retStat.GetError().empty())
SEH_LOG_ERROR("BuildMultiCallFlowTables-\tFailed to parse flow");
else
SEH_LOG_ERROR(retStat.GetError());
break;
}
}
else
{
SEH_LOG_ERROR("BuildMultiCallFlowTables-\tFailed to get baseSEHObject for: ",entry.first);
}
}
if (retStat.Success())
{
retStat = ResolveNextStateIndexes();
if (retStat.Fail())
SEH_LOG_ERROR("BuildMultiCallFlowTables-\tFailed in ResolveNextStateIndexes");
}
return retStat;
}
RetStat SehEngine::BuildSingleFlowTable(string flowPrefix, string flowFile) {
RetStat retStat;
auto cfMapIter = callFlowMap_.find(flowPrefix);
if (cfMapIter != callFlowMap_.end())
{
CallFlow* p_cf = cfMapIter->second;
p_callFlowBuilder_ = createCallFlowBuilder(flowFile);
if (p_callFlowBuilder_ != nullptr)
retStat = p_callFlowBuilder_->BuildFlowTableFromFile(flowFile, p_cf, p_baseSEHObject_);
}
else
retStat.SetFail(string("BuildSingleFlowTable-\tdid not find call flow for: ").append(flowPrefix));
return retStat;
}
ICallFlowBuilder *SehEngine::createCallFlowBuilder(string flowFile) {
int lastIndexOf = flowFile.find_last_of('.');
if (lastIndexOf != string::npos)
{
string fileExt = flowFile.substr(lastIndexOf + 1);
if(fileExt.compare("xml") == 0)
return new XMLCallFlowBuilder();
else if (fileExt.compare("json"))
return new JsonCallFlowBuilder();
}
return nullptr;
}
RetStat SehEngine::ReadAndCreateFlowsFromFile() {
RetStat retStat;
std::ifstream infile(flowsFileName_);
if (infile.is_open())
{
std::string line;
while (std::getline(infile, line))
{
if(line[0] == '#')
continue;
std::istringstream iss(line);
string flowPrefix, flowFileName;
if ((iss >> flowPrefix >> flowFileName))
{
if(!flowPrefix.empty() && !flowFileName.empty())
{
CallFlow* p_cf = new CallFlow();
callFlowMap_[flowPrefix] = p_cf;
flowFilesMap_[flowPrefix] = flowFileName;
}
}
else
{
retStat.SetFail();
SEH_LOG_ERROR(__PRETTY_FUNCTION__,"Broken Line");
}
}
}
else
{
retStat.SetFail(string("File not found: ").append(flowsFileName_));
}
return retStat;
}
RetStat SehEngine::ResolveNextStateIndex(NextState& nextState) {
RetStat retStat;
nextState.stateIndex.uiStateFlowIndex = 0; // "there can be only one"
/*************************
* Resolve the State index
*************************/
for (CallFlow* p_callFlow : callFlowArray_)
{
int iFlowIndex = 0;
if (p_callFlow->iNumOfStates > 0 && !p_callFlow->stateArray.empty())
{
int iStateIndex = 0;
for (State state : p_callFlow->stateArray)
{
if (state.stateName.compare(nextState.stateName) == 0)
{
nextState.stateIndex.uiStateFlowIndex = iFlowIndex;
nextState.stateIndex.uiStateIndex = iStateIndex;
return retStat;
}
iStateIndex++;
}
iFlowIndex++;
}
}
retStat.SetFail();
return retStat;
}
RetStat SehEngine::ResolveNextStateIndexes() {
RetStat retStat;
NextState* p_nextState = nullptr;
for (CallFlow* p_callFlow : callFlowArray_)
{
if (p_callFlow->iNumOfStates > 0 && !p_callFlow->stateArray.empty())
{
/*****************************
* going over the flow states
*****************************/
for (State statePtr : p_callFlow->stateArray)
{
/**************************
* Scanning the map events
*************************/
for (auto eventMapItr : statePtr.eventsMap)
{
EventData* p_eventData = &eventMapItr.second;
/*****************************
* checking for valid event
****************************/
if (p_eventData != nullptr && !p_eventData->Empty())
{
/********************************************
* Resolve complex actions next state if any
*******************************************/
for (EventAction action : p_eventData->actions)
{
retStat = ResolveComplexActionNextState(action);
if (retStat.Fail())
return retStat;
}
/*****************************************
* Resolving the NextState Name into index if the next
* state is empty then it means that we want to stay in
* the same state
****************************************/
if (p_nextState->IsValid())
{
retStat = ResolveNextStateIndex(p_eventData->nextState);
if (retStat.Fail())
{
retStat.SetFail(string("SEHEngine::ResolveNextStateIndexes-\tFailed to Resolve NextState : ")
.append(p_nextState->stateName));
return retStat;
}
}
}
}
/******************************
* Resolve Base State if exists
*****************************/
if (statePtr.baseState.IsValid())
{
retStat = ResolveNextStateIndex(statePtr.baseState);
if (retStat.Fail())
{
if (retStat.GetError().empty())
retStat.SetFail(string(__PRETTY_FUNCTION__)
.append("-\tFailed to Resolve BaseState : ")
.append(statePtr.baseState.stateName));
return retStat;
}
}
}
}
}
return retStat;
}
RetStat SehEngine::ResolveComplexActionNextState(EventAction &actionRef) {
RetStat retStat;
EventIfAction* p_eventIfAction;
EventWhileAction* p_eventWhileAction;
EventSwitchAction* p_eventSwitchAction;
NextState nextState;
switch (actionRef.actionType)
{
case nsEnums::eActionType_Regular:
break;
case nsEnums::eActionType_If:
p_eventIfAction = (EventIfAction*)&actionRef;
/*
* checking the true actions
*/
nextState = p_eventIfAction->trueActions.nextState;
if (nextState.IsValid())
{
retStat = ResolveNextStateIndex(nextState);
if (retStat.Fail())
{
retStat.SetFail(string(__PRETTY_FUNCTION__).append("-\tFailed to Resolve true actions NextState : ").append(nextState.stateName));
return retStat;
}
}
/*
* checking the false actions
*/
nextState = p_eventIfAction->falseActions.nextState;
if (nextState.IsValid())
{
retStat = ResolveNextStateIndex(nextState);
if (retStat.Fail())
{
retStat.SetFail(string(__PRETTY_FUNCTION__).append("-\tFailed to Resolve true actions NextState : ").append(nextState.stateName));
return retStat;
}
}
break;
case nsEnums::eActionType_While:
p_eventWhileAction = (EventWhileAction*)&actionRef;
nextState = p_eventWhileAction->whileActions.nextState;
if (nextState.IsValid())
{
retStat = ResolveNextStateIndex(nextState);
if (retStat.Fail())
{
retStat.SetFail(string(__PRETTY_FUNCTION__).append("-\tFailed to Resolve NextState in the While: ").append(nextState.stateName));
return retStat;
}
}
break;
case nsEnums::eActionType_Switch:
p_eventSwitchAction = (EventSwitchAction*)&actionRef;
/*
* going over the cases
*/
for (EventData eventData : p_eventSwitchAction->switchActions)
{
nextState = eventData.nextState;
if (nextState.IsValid())
{
retStat = ResolveNextStateIndex(nextState);
if (retStat.Fail())
{
retStat.SetFail(string(__PRETTY_FUNCTION__).append("-\tFailed to Resolve NextState in the Switch: ").append(nextState.stateName));
return retStat;
}
}
}
break;
}
return retStat;
}
RetStat SehEngine::ActivateActions(StateIndex& nextStateIndex) {
RetStat retStat;
bool b_DidLastActionFailed = false;
int iNumOfActions = this->p_eventData_->getNumOfActions();
this->activateActionData_.nextStateIndex = nextStateIndex;
this->activateActionData_.boolWasStateChanged = false;
for (EventAction eventAction : this->p_eventData_->actions)
{
this->p_eventAction_ = &eventAction;
/************************************************************
* activating the action. checking if the last action failed, if so
* then activating only mandatory actions
***********************************************************/
if (b_DidLastActionFailed)
{
if (this->p_eventAction_->isActionMandatory())
{
retStat = this->p_eventAction_->ActivateAction(this->activateActionData_);
if (retStat.Fail())
{
SEH_LOG_ERROR(string(__PRETTY_FUNCTION__).append("-\tFailed in Action: ").append(this->p_eventAction_->name));
b_DidLastActionFailed = true;
}
}
}
else // everything is o.k.
{
retStat = this->p_eventAction_->ActivateAction(this->activateActionData_);
if (retStat.Fail())
{
if (!this->p_eventAction_->isActionCritical())
{
SEH_METHOD_ERROR("-\tFailed in Action: ",this->p_eventAction_->name);
b_DidLastActionFailed = true;
}
}
}
// If state was moved to next state in the called object then we
// must not continue
if (activateActionData_.boolWasStateChanged)
break;
}
/***************************
* Move to next state
**************************/
if (!activateActionData_.boolWasStateChanged)
{
if (iNumOfActions > 0)
{
/*************************************
* Go to next State check if the state need to change
************************************/
if (p_eventData_->nextState.IsValid())
{
SEH_LOG("SehEngine-\tChanging to State: ",p_eventData_->nextState.stateName);
/*
* Setting next state
*/
nextStateIndex.uiStateFlowIndex = p_eventData_->nextState.stateIndex.uiStateFlowIndex;
nextStateIndex.uiStateIndex = p_eventData_->nextState.stateIndex.uiStateIndex;
} else
{
SEH_LOG("SehEngine-\tStaying in the same State: ",p_state_->stateName);
}
} else
{
retStat.SetFail("SehEngine::ActivateActions-\tNo actions");
}
}
return retStat;
}
SehEngine::SehEngine() {
}
RetStat SehEngine::InitMultiFlows(string &flowsFileName, map<string, IBaseSEH *>& baseSehMap) {
this->flowsFileName_.assign(flowsFileName);
maxNumberOfCallFlows_ = 1; // will be resolved from the flow file
this->baseSEHObjectMap_ = baseSehMap;
InitMembers();// InitMultiFlowsMembers();
RetStat retStat = ReadAndCreateFlowsFromFile();
if (retStat.Success())
{
/*
* set the max flows
* and current and init the callflow array
*/
maxNumberOfCallFlows_ = flowFilesMap_.size();
//callFlowArray_ = new CallFlow[maxNumberOfCallFlows_];
/*s
* setting the flows in the array
* and the flow index in the call flow
*/
int index = 0;
//Set<Entry<String, CallFlow>> entrySet = callFlowMap_.entrySet();
for (auto entry : this->callFlowMap_)
{
CallFlow& cf = *entry.second;
cf.Reset();
cf.flowIndex = index;
auto baseSEHObjectMapIterator = baseSEHObjectMap_.find(entry.first);
if (baseSEHObjectMapIterator != baseSEHObjectMap_.end())
cf.p_baseSEHObject = baseSEHObjectMapIterator->second;
callFlowArray_[index++] = entry.second; //&cf;
}
retStat = BuildMultiCallFlowTables(flowFilesMap_);
}
return retStat;
}
RetStat SehEngine::InitMultiFlows(map<string, string> &flowFilesMap, map<string, IBaseSEH *> &baseSehMap) {
maxNumberOfCallFlows_ = 1; // will be resolved from the flow file
this->baseSEHObjectMap_ = baseSehMap;
InitMembers();
/*
* set the max flows
* and current and init the callflow array
*/
maxNumberOfCallFlows_ = flowFilesMap.size();
//callFlowArray_ = new CallFlow[maxNumberOfCallFlows_];
/*
* Init Call flow map
*/
int index = 0;
//Set<Entry<String, String>> entrySet = flowFilesMap_.entrySet();
for (auto entry : flowFilesMap)
{
CallFlow* p_cf = new CallFlow();
p_cf->Reset();
callFlowMap_[entry.first] = p_cf;
p_cf->flowIndex = index;
auto baseSEHObjectMapIterator = baseSEHObjectMap_.find(entry.first);
if (baseSEHObjectMapIterator != baseSEHObjectMap_.end())
p_cf->p_baseSEHObject = baseSEHObjectMapIterator->second;
callFlowArray_[index++] = p_cf;
}
return BuildMultiCallFlowTables(flowFilesMap);
}
RetStat SehEngine::HandleEvent(StateIndex& stateIndex, string& eventStr) {
RetStat retStatus;
CallFlow* p_callFlow = nullptr;
/********************
* Validating
********************/
/******************************
* Reseting the working params Getting the Session State
*****************************/
this->p_stateIndex_ = &stateIndex;
/*************************
* Validate State indexes
************************/
if (this->p_stateIndex_->uiStateFlowIndex < this->maxNumberOfCallFlows_)
{
p_callFlow = this->callFlowArray_[this->p_stateIndex_->uiStateFlowIndex];
if (this->p_stateIndex_->uiStateIndex < p_callFlow->iNumOfStates)
{
/*************************************************
* Getting the EventData from State/Event/Party
* and setting the BaseSEH object
***********************************************/
this->p_state_ = &p_callFlow->stateArray[this->p_stateIndex_->uiStateIndex];
p_eventData_ = (EventData*)GetFromMap(this->p_state_->eventsMap,eventStr);
this->p_baseSEHObject_ = p_callFlow->p_baseSEHObject;
//this->activateActionData_.object = p_callFlow->baseSEHObject;;
string& eventName = eventStr; //this.baseSEHObject.resolveEventName(iEvent);
if (!eventName.empty())
SEH_METHOD_LOG("-\tState/Event: ",this->p_state_->stateName,'/',eventName);
/**********************************************
* if no implementation for this State/Event then looking if
* there is a BaseState
*********************************************/
if ((this->p_eventData_ == nullptr || this->p_eventData_->getNumOfActions() == 0)
&& (this->p_state_->baseState.IsValid()))
{
this->p_stateIndex_ = &this->p_state_->baseState.stateIndex;
this->p_state_ = &p_callFlow->stateArray[this->p_stateIndex_->uiStateIndex];
this->p_eventData_ = (EventData *) GetFromMap(this->p_state_->eventsMap, eventStr); // eventCellsArray[iEvent];
}
if (this->p_eventData_ != nullptr)
{
// logger.severe("SEHEngine::HandleEvent-\tEvent: "
// + eventName + " Not Implemented for State: "
// + this.statePtr.stateName);
// retStatus.setFail();
// return retStatus;
// }
/*************************
* Get & Activate Actions
************************/
retStatus = ActivateActions(*this->p_stateIndex_);
}
else
{
SEH_METHOD_ERROR("-\tEvent: ",eventName," Not Implemented for State: ",this->p_state_->stateName);
retStatus.SetFail();
}
} else
{
SEH_METHOD_ERROR("-\tWrong State index");
retStatus.SetFail();
//return retStatus;
}
} else
{
SEH_METHOD_ERROR("-\tWrong Flow index");
retStatus.SetFail();
}
return retStatus;
}
const string &SehEngine::GetStateName(StateIndex &stateIndex) {
if (stateIndex.uiStateFlowIndex < maxNumberOfCallFlows_)
{
if (stateIndex.uiStateIndex < callFlowArray_[stateIndex.uiStateFlowIndex]->iNumOfStates)
return callFlowArray_[stateIndex.uiStateFlowIndex]->stateArray[stateIndex.uiStateIndex].stateName;
else
return nsConstants::C_WRONG_SEH_STATE;
}
return nsConstants::C_WRONG_SEH_STATE;
}
RetStat SehEngine::GetStateIndex(StateIndex &stateIndex, string &stateName) {
RetStat retStatus;
int iStateIndex = 0;
if (!stateName.empty())
{
for (auto& callFlowEntry : this->callFlowMap_)
{
/**************************
* finding the state
*************************/
for (State& state : callFlowEntry.second->stateArray)
{
if (state.stateName.compare(stateName) == 0)
{
stateIndex.uiStateFlowIndex = callFlowEntry.second->flowIndex;
stateIndex.uiStateIndex = iStateIndex;
return retStatus;
}
iStateIndex++;
}
}
SEH_METHOD_ERROR("-\tThe state: ",stateName," does not exists");
retStatus.SetFail();
}
else
{
stateIndex.uiStateFlowIndex = 0;
stateIndex.uiStateIndex = 0;
}
return retStatus;
}
// Created by amir on 07/09/16.
//
#ifndef SEH_SEH_ENGINE_H
#define SEH_SEH_ENGINE_H
#include "../defs/seh_types.h"
using namespace std;
class SehEngine {
private:
ICallFlowBuilder* p_callFlowBuilder_;
string flowsFileName_;
vector<CallFlow*> callFlowArray_;
map<string, CallFlow*> callFlowMap_;
map<string, string> flowFilesMap_;
int currentCallFlowIndex;
int maxNumberOfCallFlows_;
int startChildCallFlows;
State* p_currentFirstState_;
EventAction eventAction_;
EventData eventData_;
StateIndex* p_stateIndex_;
State* p_state_;
EventData* p_eventData_;
ActivateActionData activateActionData_;
//TreeModel xmlTreeModel;
string errorMsg_;
int currentFlowNumOfStates_;
string actionName_;
string eventName_;
IBaseSEH* p_baseSEHObject_;
map<string, IBaseSEH*> baseSEHObjectMap_;
AFP actionFunc_;
map<string,StateIndex> stateIndexMap_;
EventAction* p_eventAction_;
void Reset();
void InitMembers();
/**
* Reading the flows from the file and parsing each flow
*
* @return RetStat
*/
RetStat BuildMultiCallFlowTables(map<string, string>& flowFilesMap);
/**
* Reading and parsing a single flow file
*
* @return
*/
RetStat BuildSingleFlowTable(string flowPrefix, string flowFile);
ICallFlowBuilder* createCallFlowBuilder(string flowFile);
RetStat ReadAndCreateFlowsFromFile();
/**
* Resolving the next state index from the state name here there is only one
* call flow so wre don't need to resolve which call flow (for now)
*/
RetStat ResolveNextStateIndex(NextState& nextState);
/**
* Resolving the state index from the state name + flow name : Going over
* the valid call-flows, going over each state and its events and resolving
* the actions next state
*/
RetStat ResolveNextStateIndexes();
/**
* Resolves complex actions that have next state inside them like
* switch/if/while actions
*
* @param actionPtr
* @return
*/
RetStat ResolveComplexActionNextState(EventAction& actionRef);
/**
* activating the actions and moving to the next state
*
* @param nextStateIndex
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
RetStat ActivateActions(StateIndex& nextStateIndex);
public:
SehEngine();
/**
* Initialize the engine with a list of flows , each flow is attached to a
* BaseSEH class
*
* @param flowsFileName
* @param baseSehMap
* @param iMaxNumOfCallFlows
* @return
* @throws SecurityException
* @throws NoSuchMethodException
*/
RetStat InitMultiFlows(string& flowsFileName, map<string, IBaseSEH*>& baseSehMap);
RetStat InitMultiFlows(map<string, string>& flowFilesMap, map<string, IBaseSEH*>& baseSehMap);
/**
* Handling the State/Event : This method is what this is all about, getting
* the State/Event and activating the resolved actions and setting the next
* state
*
* @param stateIndex
* @param iEvent
* @return
*/
RetStat HandleEvent(StateIndex& stateIndex, string& eventStr);
/**
* Handling the State/Event : This method is what this is all about, getting
* the State/Event and activating the resolved actions and setting the next
* state
* @param stateIndex
* @param eventStr
* @param p_appData
* @return
*/
RetStat HandleEvent(StateIndex stateIndex, string& eventStr /*int iEvent */, void* p_appData)
{
this->p_baseSEHObject_->setAppData(p_appData);
return HandleEvent(stateIndex, eventStr);
}
/**
* Getting the state name from the stateIndex
*
* @param stateIndex
* @return
*/
const string& GetStateName(StateIndex& stateIndex);
int GetCurrentNumOfCallFlows() { return maxNumberOfCallFlows_; }
/**
* Getting the stateIndex from the State Name and flow file
*
* @param stateIndex
* @param flowFileName
* @param ba_StateName
* @return
*/
RetStat GetStateIndex(StateIndex& stateIndex, string& stateName);
};
#endif //SEH_SEH_ENGINE_H
//
// Created by amir on 04/09/16.
//
#include <iostream>
#include <functional>
#include <vector>
typedef std::function<int (int, int)> INTINT_FUNC;
using namespace std::placeholders;
class TestAdd
{
public:
int adding(int a, int b) { return a + b; }
INTINT_FUNC resolveFunc() { return std::bind(&TestAdd::adding,this,_1,_2); }
};
class TestSub
{
public:
int subbing (int a, int b) { return a - b; }
INTINT_FUNC resolveFunc() { return std::bind(&TestSub::subbing,this,_1,_2); }
};
void testArrays()
{
struct IntPtr
{
int a;
void* p;
IntPtr(int a) : a(a) {}
IntPtr() {}
};
std::vector<IntPtr> intPtrArray;
for (int i = 0; i < 10; ++i) {
IntPtr ip;
ip.a = i;
intPtrArray.push_back(ip);
}
for (auto itr : intPtrArray)
std::cout << itr.a << std::endl;
}
int main() {
INTINT_FUNC func;
testArrays();
return 0;
std::cout << "Hello, World!" << std::endl;
TestAdd testAdd;
TestSub testSub;
func = testAdd.resolveFunc();
std::cout << "result is: " << func(20,10) << std::endl;
func = testSub.resolveFunc();
std::cout << "result is: " << func(20,10) << std::endl;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment