private void EnsureRoutineHubKey(RoutineName routineName) { if (!this.RoutineHub.ContainsKey(routineName)) { this.RoutineHub.Add(routineName, new Queue <IRoutineItem>()); } }
private T Run <T>(RoutineName routineName, IRoutineItem r, Feedback feedback, object[] args) { r.BroadCastMessage = feedback.Success.Value; // Set the broadcast message. Other values are set during registration. var request = Request.Create(r.CommandName, r.BroadCastMessage, args); var response = new Response(request, request.Message + "[Routine: " + routineName + "]", ResponseTypes.Success); var result = (T)r.Action.DynamicInvoke(args); response.Entity = result; response.Type = result.GetType(); response.EventName = r.EventName; response.Message = request.Message ?? String.Format(ResponseMessage, "N/A", r.Action.Method.Name, response.Type.Name); this.CommandStream.Enqueue(new CommandStreamItem() { Command = r.CommandName, Response = response }); // Broadcase the response to all listeners. this.Broadcast(response); return(result); }
internal override bool MatchesInvoke(Invoke request, IQuery query) { if (request == null) { return(false); } bool ignoreCase = true; if (query != null) { ignoreCase = query.IgnoreIdentifiersCase(); } if (!RoutineName.Equals(request.RoutineName, ignoreCase)) { return(false); } // TODO: add a better resolution to obtain the final type of the argument // and compare it to the parameter type definition bool unboundedSeen = false; for (int i = 0; i < request.Arguments.Length; i++) { var argType = request.Arguments[i].ReturnType(query, null); if (i + 1 > Parameters.Length) { if (!unboundedSeen) { return(false); } // TODO: verify the type of the argument (how to evaluate?) } else { var param = Parameters[i]; unboundedSeen = param.IsUnbounded; var paramType = param.Type; if (!paramType.IsComparable(argType)) { return(false); } } } if (!unboundedSeen && request.Arguments.Length != Parameters.Length) { return(false); } return(true); }
public T RollBack <T>(RoutineName routineName, Feedback feedback, object[] args) { if (!this.RoutineHub.ContainsKey(routineName)) { throw new ArgumentException("There is no routine by this name registered."); } if (this.RoutineHub[routineName].FirstOrDefault(x => x.Rollback == null) != null) { throw new InvalidDataException("There is a method in this routine without a RollBack function assigned. This routine is not eligable for RollBack."); } var result = default(T); var reverse = this.RoutineHub[routineName].Reverse().ToList(); for (var i = (reverse.Count - 1); i >= 0; i--) { var request = Request.Create(reverse[i].CommandName, reverse[i].BroadCastMessage + "[Rolling Back Routine: " + routineName + "][" + (i - 1) + "/" + reverse.Count() + "]", args); var response = new Response( request, request.Message + "[Routine: " + routineName + "] [Executing Rollback Method: " + reverse[i].Rollback.Method.Name + "]", ResponseTypes.Success) { EventName = reverse[i].EventName }; try { result = (T)reverse[i].Rollback.DynamicInvoke(args); response.Entity = result; // Broadcase the response to all listeners. this.Broadcast(response); } catch (TargetInvocationException rollbackException) { this.BroadCast(rollbackException, request); response.Message = "[All is lost. RollBack method failed]" + response.Message; response.ResponseType = ResponseTypes.Error; this.CommandStream.Enqueue(new CommandStreamItem() { Command = reverse[i].CommandName, Response = response }); // Broadcase the response to all listeners. this.Broadcast(response); break; } } return(result); }
public T Run <T>(RoutineName routineName, Feedback feedback, object[] args) { var result = default(T); var routine = this.RoutineHub[routineName].ToList(); for (var i = 0; i < routine.Count - 1; i++) { try { result = this.Run <T>(routineName, routine[i], new Feedback() { Success = new Resource() { Value = "(Routine: " + routineName + ")(" + (i + 1) + "/" + routine.Count + ")" } }, args); //Replace whatever T was that was passed in. int index = Array.FindIndex(args, x => x.GetType() == typeof(T) || x.GetType().IsSubclassOf(typeof(T))); args[index] = result; } catch (Exception ex) { var request = Request.Create(routine[i].CommandName, routine[i].BroadCastMessage, args); var exResponse = this.BroadCast(ex, request); try { // If we have a fail over action then try it. if (routine[i].FailOver != null) { try { result = this.FailOver <T>(routineName, request, exResponse.ResponseId, routine[i], args); } catch (Exception failOverException) { this.BroadCast(failOverException, request); throw; } } else { throw; } } catch (Exception deepEx) { this.BroadCast(deepEx, request); throw; } } } return(result); }
internal override bool MatchesInvoke(Invoke invoke, IRequest request) { if (invoke == null) { return(false); } if (!RoutineName.Equals(invoke.RoutineName)) { return(false); } // TODO: add a better resolution to obtain the final type of the argument // and compare it to the parameter type definition bool unboundedSeen = false; for (int i = 0; i < invoke.Arguments.Length; i++) { var argType = invoke.Arguments[i].Value.ReturnType(request, null); if (i + 1 > Parameters.Length) { if (!unboundedSeen) { return(false); } // TODO: verify the type of the argument (how to evaluate?) } else { var param = Parameters[i]; unboundedSeen = param.IsUnbounded; var paramType = param.Type; if (!paramType.IsComparable(argType)) { return(false); } } } if (!unboundedSeen && invoke.Arguments.Length != Parameters.Length) { return(false); } return(true); }
internal override bool MatchesInvoke(Invoke invoke, IQuery query) { if (invoke == null) { return(false); } bool ignoreCase = true; if (query != null) { ignoreCase = query.IgnoreIdentifiersCase(); } if (!RoutineName.Equals(invoke.RoutineName, ignoreCase)) { return(false); } var inputParams = Parameters.Where(parameter => parameter.IsInput).ToList(); if (invoke.Arguments.Length != inputParams.Count) { return(false); } for (int i = 0; i < invoke.Arguments.Length; i++) { // TODO: support variable evaluation here? or evaluate parameters before reaching here? if (!invoke.Arguments[i].IsConstant()) { return(false); } var argType = invoke.Arguments[i].ReturnType(query, null); var paramType = Parameters[i].Type; // TODO: verify if this is assignable (castable) ... if (!paramType.IsComparable(argType)) { return(false); } } return(true); }
/// <summary> /// Register with the routine hub, which is used to chain command actions and provide failover and rollback options /// </summary> /// <typeparam name="T">The type of the parameter which will be passed between actions.</typeparam> /// <param name="routineName">Name of the routine to associate this command name, event name, and action.</param> /// <param name="commandName">Name of the command to register</param> /// <param name="eventName">Broadcast channel</param> /// <param name="action">Called as the primary/preferred target</param> /// <param name="failOver">Optional. Will be called on error of the 'action'</param> /// <param name="rollBack">Optional. In the advent of an error that can't be solved by action or failover. Once this level is reached the command queue will stop processing.</param> public void Register <T>(RoutineName routineName, CommandName commandName, EventName eventName, Func <T, Feedback, T> action, Func <T, Feedback, T> failOver = null, Func <T, Feedback, T> rollBack = null) { try { this.EnsureRoutineHubKey(routineName); this.RoutineHub[routineName].Enqueue(new RoutineItem { CommandName = commandName, EventName = eventName, Action = action, FailOver = failOver, Rollback = rollBack }); // wireup the action associated with this command, and the event channel to broadcast to when this command is processed. } catch (Exception ex) { var msg = string.Format(ResponseMessage, "Registration failed with msg: " + ex.Message, action.Method.Name, typeof(T).Name); this.Broadcast(new Response { Entity = ex, Type = ex.GetType(), EventName = EventName.OnException, Message = msg }); } }
internal override bool MatchesInvoke(Invoke invoke, IRequest request) { if (invoke == null) { return(false); } if (!RoutineName.Equals(invoke.RoutineName)) { return(false); } var inputParams = Parameters.Where(parameter => parameter.IsInput).ToList(); if (invoke.Arguments.Length != inputParams.Count) { return(false); } for (int i = 0; i < invoke.Arguments.Length; i++) { if (!invoke.Arguments[i].Value.IsConstant()) { return(false); } var argType = invoke.Arguments[i].Value.ReturnType(request, null); var paramType = Parameters[i].Type; // TODO: verify if this is assignable (castable) ... if (!paramType.IsComparable(argType)) { return(false); } } return(true); }
private T FailOver <T>(RoutineName routineName, Request request, Guid exResponseId, IRoutineItem r, object[] args) { request.Message = request.Message; var response = new Response(request, "", ResponseTypes.Success); var result = (T)r.FailOver.DynamicInvoke(args); response.Entity = result; response.Type = result.GetType(); response.EventName = r.EventName; response.Message = "[Executing Failover Method: " + r.FailOver.Method.Name + "]" + String.Format(ResponseMessage, "N/A", r.Action.Method.Name, response.Type.Name); this.CommandStream.Enqueue(new CommandStreamItem() { Command = r.CommandName, Response = response }); // Broadcase the response to all listeners. this.Broadcast(response); return(result); }