public virtual void OnCallAfter(ModelAction action, ModelParameters parameters, object result) { //Note: Override if you want to do after if (CallAfter != null) { CallAfter(action, parameters, result); } }
public virtual object Clone() { ModelAction clone = (ModelAction)this.MemberwiseClone(); //Clone the collections, so add/remove is independent clone._requirements = (ModelRequirements)this.Requirements.Clone(); clone._parameters = (ModelParameters)this.Parameters.Clone(); return(clone); }
public virtual bool OnCallBefore(ModelAction action, ModelParameters parameters) { //Note: Override if you want to do something, or call other methods BEFORE execution of the action bool result = true; //true, indicates continue to call the action if (_callbefore != null) { foreach (CallBeforeHandler handler in _callbefore) { result &= handler(action, parameters); } } return(result); }
protected ModelParameters DetermineParameters(ModelAction action) { try { ModelParameters allparameters = action.Parameters; ModelParameters choosen = new ModelParameters(); //Loop through the method parameters foreach (ParameterInfo info in action.Method.GetParameters()) { //Find the all parameters assoicated with this param ModelParameters parameters = allparameters.Find(info.Name); //Exclude invalid parameters (if not requested) if (!this.InvalidParameters) { parameters = (ModelParameters)parameters.FindFlag((int)ModelItemFlags.Throws, false); } if (parameters.Count <= 0) { throw new ModelException(this, "Unable to find a ModelParameter for method parameter: '" + info.Name + "'"); } //Choose one of the parameters, based upon weight ModelParameter parameter = parameters.Choose(this); parameter.Accessed++; //Note: We cloning the param, since were choosing only one of the values to use this time. parameter = (ModelParameter)parameter.Clone(); //Choose (or generate) one of the values ModelValue value = DetermineParameterValue(parameter); value.Accessed++; //Add it to the array parameter.Value = value; choosen.Add(parameter); } return(choosen); } catch (Exception e) { //Make this easier to debug throw new ModelException(this, "DetermineParameters", e); } }
public virtual void OnException(ModelAction action, ModelParameters parameters, Exception e) { //Since were using reflection, if an error occurs within the method //make this easier to debug (for the method writer) so they see their exception //instead of the reflection based one. while (e.InnerException != null && e is TargetInvocationException) { e = e.InnerException; } //Find what should have thrown the exception, action or parameters Type exception = action.Exception; string exceptionid = action.ExceptionId; if (exception == null && exceptionid == null) { //Otherwise maybe one of the parameters was supposed to throw //Find the parameter that expects an error ModelParameters found = (ModelParameters)parameters.FindFlag((int)ModelItemFlags.Throws); if (found.Count > 0) { //Note: We find the 'highest' weighted parameter (ie: order of errors processed) found.SortByWeightDesc(); exception = found.First.Exception; exceptionid = found.First.ExceptionId; } } //Exception not expected if (exception == null && exceptionid == null) { throw new ModelException(action, "Threw an exception: " + e.Message, e); } //Expected: Simple verification, type based if (exception != null && (exception != e.GetType())) { throw new ModelException(action, "Threw the wrong exception: " + e.Message, e); } //Expected: Advanced verification, user implemented function if (exceptionid != null) { this.OnException(action, parameters, e, exceptionid); //Throws if not verified } }
private void ExecuteAction(ModelAction action) { //CallBefore, actions //TODO: What happens if this now meets the requirements? foreach (ModelAction before in this.GetPossibleActions(action.Model.Actions.FindFlag(ModelActionFlags.CallBefore))) { this.ExecuteActionInfo(new ModelActionInfo(before, this.DetermineParameters(before), null)); } //Execute Action this.ExecuteActionInfo(new ModelActionInfo(action, this.DetermineParameters(action), null)); //CallAfter, actions //TODO: What happens if this now meets the requirements? foreach (ModelAction after in this.GetPossibleActions(action.Model.Actions.FindFlag(ModelActionFlags.CallAfter))) { this.ExecuteActionInfo(new ModelActionInfo(after, this.DetermineParameters(after), null)); } }
public ModelRequirement(ModelAction action, ModelRequirementAttribute attr, ModelVariable variable, ModelValue value) : base(action != null ? action.Model : null, attr) { //Action _action = action; //Variable if (variable != null) { _variable = variable; if (variable.BitMask) { this.BitMask = true; } } //if(_variable == null) // throw new ModelException(this, "An empty variable is not a valid requirement", null); //Only override the attr, if values are really specified if (value != null) { _values = new ModelValues(value); } //BitMask //TODO: Better place to expand this, (incase values added later). if (this.BitMask) { this.AddBitCombinations(); } //Infer dynamic variable(s) this.InferDynamicVariables(); //Requirements assoicated with actions, are not global. They are tied to that particular //instance of the model, and it's instance of state variables. However if not assoicated //with actions, the default behavior is that their global, they apply to all models //that contain that state variable, unless explicitly indicated otherwise. _global = (action == null); }
//Constructor public ModelParameter(ModelAction action, ModelParameterAttribute attr, ParameterInfo paraminfo) : base(action != null ? action.Model : null, attr) { _action = action; _paraminfo = paraminfo; //Infer values from the type, if not specified if (attr != null && attr.Type != null) { this.AddValuesFromType(attr, null); } //BitMask //TODO: Better place to expand this, (incase values added later). if (this.BitMask) { this.AddBitCombinations(); } //Infer dynamic variable(s) this.InferDynamicVariables(); }
//Constructor public ModelActionInfo(ModelAction action, ModelParameters parameters, object retval) { _action = action; _parameters = parameters; _retval = retval; }
private void ExecuteActionInfo(ModelActionInfo actioninfo) { ModelAction action = actioninfo.Action; ModelParameters parameters = actioninfo.Parameters; Model model = action.Model; //Pre-Execute, events //Note: If CallBefore returns false, we simply don't execute the method if (model.OnCallBefore(action, parameters)) { //Adding the selected action (and its param values) to the trace. if (this.Options.Tracing) { _actionstrace.Add(actioninfo); } //Execute the method (delegate) actioninfo.RetVal = action.Execute(parameters); _actionscalled++; //Add the returned model to the system Model output = actioninfo.RetVal as Model; if (output != null) { //If it doesn't already exist, and the model type is part of the set if (this.Models.FindInstance(output) == null) { actioninfo.Created = true; //Add returned models, if requested if (this.Options.AddReturnedModels) { //Note: We always obey the maxinstance count Models found = (Models)this.Models.FindType(output.GetType()).FindFlag((int)ModelItemFlags.Disabled, false); if (found.Count < output.MaxInstances) { output.Enabled = true; //Enabled by default if (output.ParentModel == null) //Hook up the creator, if not already specified { output.ParentModel = action.Model; } this.Models.Add(output); } } } } //Trace if (this.Options.Tracing) { ModelTrace.WriteLine(ModelTrace.FormatMethod(actioninfo)); } //Post-Execute, events model.OnCallAfter(action, parameters, actioninfo.RetVal); } //Reset cached variables foreach (ModelVariable variable in this.Models.Variables) { variable.CachedValue = null; } }
protected virtual bool Execute(ModelRequirements requirements, long startingticks, long remainingticks) { bool meetsrequirements = false; _actionscalled = 0; //Continue until no more actions to execute ModelAction action = this.DetermineNextAction(); while (action != null) { //Model Model model = action.Model; //Init if (model.Actions.Accessed == 0) { model.Init(); } //CallFirst, actions //TODO: What happens if this now meets the requirements? foreach (ModelAction first in this.GetPossibleActions(model.Actions.FindFlag(ModelActionFlags.CallFirst))) { if (first != action) { this.ExecuteAction(first); } } //Execute (choose the parameters as well) //Note: CallFirst might have disabled this model, so we check first if (model.Enabled) { this.ExecuteAction(action); } //Determine if all the requirements were met if (requirements != null && requirements.Count > 0 && MeetsRequirements(requirements)) { meetsrequirements = true; break; } //Check action count if (_actionscalled >= _options.MaxActions) { if (this.Options.Tracing) { ModelTrace.WriteLine("MaxActions: '" + _options.MaxActions + "' was reached."); } break; } //Check Timeout long currentticks = DateTime.Now.Ticks; if (currentticks - startingticks > remainingticks) { if (this.Options.Tracing) { ModelTrace.WriteLine("Timeout: '" + _options.Timeout + "' has elapsed."); } break; } //Determine the next action action = this.DetermineNextAction(); } return(meetsrequirements); }
protected ModelActions GetPossibleActions(ModelActions totalactions) { //Loop through all actions, specified ModelActions possibleactions = new ModelActions(); foreach (ModelAction action in totalactions) { //Ignore Disabled actions if (action.Weight == 0 || action.Disabled) { continue; } //Ignore CallLimit/CallOnce actions that have already been called (max times) if (action.Accessed >= action.CallLimit) { continue; } //Note: CallFirst and CallLast imply CallOnce if (action.Accessed > 0 && (action.CallFirst || action.CallLast)) { continue; } //Ignore Actions, that return Models when were over the limit of those models Type returntype = action.Method.ReturnType; if (!returntype.IsPrimitive && typeof(Model).IsAssignableFrom(returntype) && returntype != typeof(Model)) { Models found = (Models)this.Models.FindType(returntype).FindFlag((int)ModelItemFlags.Disabled, false); if (found.Count >= found.MaxInstances) { continue; } } //Determine if Requirements meet ModelRequirement failedrequirement = null; bool matched = MeetsRequirements(action.Requirements, out failedrequirement); if (matched) { //Requirements met, action can be called possibleactions.Add(action); } else { //Requirements not met, action can't be called //Unless the user wants this to be called, when the requirements aren't met if (this.InvalidActions && failedrequirement != null && failedrequirement.Throws) { //Note: We clone the action, and set the expected exception, just as if //it were an invalid action from the start. We also set the weight of the //invalid action, to the weight of the requirement, so it's not weighted //the same as the (positive) version that's specified at the action level ModelAction invalidaction = (ModelAction)action.Clone(); invalidaction.Exception = failedrequirement.Exception; invalidaction.ExceptionId = failedrequirement.ExceptionId; invalidaction.Weight = failedrequirement.Weight; possibleactions.Add(invalidaction); } } } possibleactions.SortByWeightDesc(); //Sort all actions, across models return(possibleactions); }
public virtual void OnException(ModelAction action, ModelParameters parameters, Exception e, string id) { //Override this method, and verify the ExceptionId specified in the model throw new ModelException(this, "ExceptionId was specified and not verified. Override Model.VerifyException, and verify the ExceptionId as was specified in the model", e); }
public ModelRequirement(ModelAction action, ModelVariable variable, ModelValue value) : this(action, null, variable, value) { //Delegate }