Exemple #1
0
        /// <summary>
        /// Select an applicable function without executing it
        /// </summary>
        /// <typeparam name="T">Generic type</typeparam>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="conditionalPredicate">The conditional predicate.</param>
        /// <param name="functions">array of gated functions</param>
        /// <param name="keepContext">controls whether async operation should keep the synchronization context</param>
        /// <remarks>
        /// keep context should be set to true in code which is async end to end,
        /// and false in other cases to avoid deadlocking
        /// </remarks>
        /// <returns>a function to perform, never null</returns>
        public static Func <Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate,
                                                          GatedAsyncFunc <T>[] functions, bool keepContext)
        {
            Tuple <GatedAsyncFunc <T>, IGate[]> action = SelectCode(context, conditionalPredicate, functions);

            if (action?.Item1 == null)
            {
                return(() => Task.FromResult(default(T)));
            }

            return(async() =>
            {
                context.EnterScopes(mode, action.Item2);

                try
                {
                    if (action.Item1.Func != null)
                    {
                        return await action.Item1.Func().ConfigureAwait(keepContext);
                    }
                }
                finally
                {
                    context.ExitScopes(mode, action.Item2);
                }

                return default(T);
            });
        }
Exemple #2
0
        /// <summary>
        /// Select an applicable function without executing it
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="functions">array of gated functions</param>
        /// <param name="keepContext">controls whether async operation should keep the synchronization context</param>
        /// <remarks>
        /// keep context should be set to true in code which is async end to end,
        /// and false in other cases to avoid deadlocking
        /// </remarks>
        /// <returns>a function to perform, never null</returns>
        public static Func <T, Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, GatedAsyncFunc <T, T>[] functions, bool keepContext)
        {
            Tuple <GatedAsyncFunc <T, T>, IGate[]> action = SelectCode(context, null, functions);

            if (action != null && action.Item1 != null)
            {
                return(async t =>
                {
                    context.EnterScopes(mode, action.Item2);

                    try
                    {
                        if (action.Item1.Func != null)
                        {
                            return await action.Item1.Func(t).ConfigureAwait(keepContext);
                        }
                    }
                    finally
                    {
                        context.ExitScopes(mode, action.Item2);
                    }

                    return t;
                });
            }

            return(Task.FromResult);
        }
Exemple #3
0
 /// <summary>
 /// Exit a scope for gated code
 /// </summary>
 /// <param name="context">the gate context</param>
 /// <param name="mode">mode that code should be performed (e.g. scoped or not)</param>
 /// <param name="gate">the gate to exit scope for</param>
 public static void ExitScope(this IGateContext context, GatedCode.Modes mode, IGate gate)
 {
     if (context.ShouldBeScoped((mode & GatedCode.Modes.ExitScope), gate))
     {
         context.ExitScope(gate);
     }
 }
Exemple #4
0
        /// <summary>
        /// Should the context scope the code
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="mode">preferred mode for code</param>
        /// <param name="gate">gate to run</param>
        /// <returns>true if the context should scope the code, false otherwise</returns>
        private static bool ShouldBeScoped(this IGateContext context, GatedCode.Modes mode, IGate gate)
        {
            if (gate == null)
            {
                return(false);
            }

            if (context == null)
            {
                return(false);
            }

            if ((mode & GatedCode.Modes.EnterScope) == GatedCode.Modes.EnterScope ||
                (mode & GatedCode.Modes.ExitScope) == GatedCode.Modes.ExitScope)
            {
                return(true);
            }

            if (context.Request != null && context.Request.RequestedGateIds != null &&
                context.Request.RequestedGateIds.Contains(gate.Name))
            {
                return(true);
            }

            return(false);
        }
Exemple #5
0
        /// <summary>
        /// Select an applicable function without executing it
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="functions">array of gated functions</param>
        /// <returns>a function to perform, never null</returns>
        public static Func <T, T> SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, params GatedFunc <T, T>[] functions)
        {
            Tuple <GatedFunc <T, T>, IGate[]> action = SelectCode(context, null, functions);

            if (action != null && action.Item1 != null)
            {
                return(new Func <T, T>(
                           (t) =>
                {
                    context.EnterScopes(mode, action.Item2);

                    try
                    {
                        if (action.Item1.Func != null)
                        {
                            return action.Item1.Func(t);
                        }
                    }
                    finally
                    {
                        context.ExitScopes(mode, action.Item2);
                    }

                    return t;
                }));
            }

            return(new Func <T, T>((t) => t));
        }
Exemple #6
0
        /// <summary>
        /// Select an applicable action without executing it
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="conditionalPredicate">The conditional predicate.</param>
        /// <param name="actions">array of gated actions</param>
        /// <param name="keepContext">controls whether async operation should keep the synchronization context</param>
        /// <remarks>
        /// keep context should be set to true in code which is async end to end,
        /// and false in other cases to avoid deadlocking
        /// </remarks>
        /// <returns>an action to perform, never null</returns>
        public static Func <Task> SelectAction(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, GatedAsyncAction[] actions, bool keepContext = false)
        {
            Tuple <GatedAsyncAction, IGate[]> action = SelectCode(context, conditionalPredicate, actions);

            if (action?.Item1 == null)
            {
                return(s_noOpAction);
            }

            return(async() =>
            {
                context.EnterScopes(mode, action.Item2);

                try
                {
                    if (action.Item1?.Action != null)
                    {
                        await action.Item1.Action().ConfigureAwait(keepContext);
                    }
                }
                finally
                {
                    context.ExitScopes(mode, action.Item2);
                }
            });
        }
Exemple #7
0
        /// <summary>
        /// Select an applicable function without executing it
        /// </summary>
        /// <typeparam name="T">Generic type</typeparam>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="conditionalPredicate">The conditional predicate.</param>
        /// <param name="functions">array of gated functions</param>
        /// <returns>a function to perform, never null</returns>
        public static Func <T> SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate,
                                                  params GatedFunc <T>[] functions)
        {
            Tuple <GatedFunc <T>, IGate[]> action = SelectCode(context, conditionalPredicate, functions);

            if (action != null && action.Item1 != null)
            {
                return(new Func <T>(
                           () =>
                {
                    context.EnterScopes(mode, action.Item2);

                    try
                    {
                        if (action.Item1.Func != null)
                        {
                            return action.Item1.Func();
                        }
                    }
                    finally
                    {
                        context.ExitScopes(mode, action.Item2);
                    }
                    return default(T);
                }));
            }

            return(new Func <T>(() => default(T)));
        }
Exemple #8
0
        /// <summary>
        /// Is the gate combination applicable
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="gate">applicable gate, always null</param>
        /// <returns>true if no gates are applicable, false otherwise</returns>
        public override bool IsApplicable(IGateContext context, out IGate[] gate)
        {
            bool isApplicable = !base.IsApplicable(context, out gate);

            gate = null;
            return(isApplicable);
        }
Exemple #9
0
 /// <summary>
 /// Perform each function that is applicable in the current gate context. The input parameter
 /// is passed to the first applicable function, and the result of that function is used as the input
 /// for the next applicable function, etc. This allows for chaining multiple functions, each having
 /// an opportunity to modify the input.
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="input">the input object</param>
 /// <param name="mode">mode to run the gated code in</param>
 /// <param name="functions">array of gated functions</param>
 /// <typeparam name="T">the return type of the function</typeparam>
 /// <returns>instance of T (default if no applicable action found)</returns>
 public static T PerformEachFunction <T>(this IGateContext context, GatedCode.Modes mode, T input, params GatedFunc <T, T>[] functions)
 {
     Array.ForEach(functions,
                   (function) =>
     {
         input = SelectFunction(context, mode, function)(input);
     }
                   );
     return(input);
 }
Exemple #10
0
        /// <summary>
        /// Enters a collection of scopes in a nested way.
        /// </summary>
        /// <param name="context">The gate context.</param>
        /// <param name="mode">The mode that code should be performed.</param>
        /// <param name="gates">The array of gates for the scope.</param>
        public static void EnterScopes(this IGateContext context, GatedCode.Modes mode, IGate[] gates)
        {
            if (gates == null)
            {
                return;
            }

            foreach (IGate gate in gates)
            {
                EnterScope(context, mode, gate);
            }
        }
Exemple #11
0
        /// <summary>
        /// Exits a collection of scopes in a reverse order.
        /// </summary>
        /// <param name="context">The gate context.</param>
        /// <param name="mode">The mode that code should be performed.</param>
        /// <param name="gates">The array of gates for exiting the scope.</param>
        public static void ExitScopes(this IGateContext context, GatedCode.Modes mode, IGate[] gates)
        {
            if (gates == null)
            {
                return;
            }

            for (int i = gates.Length - 1; i >= 0; i--)
            {
                ExitScope(context, mode, gates[i]);
            }
        }
Exemple #12
0
        /// <summary>
        /// Is the gate combination applicable
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="gates">applicable gate, always set if the gate combination is applicable</param>
        /// <returns>true if at least one gate is applicable</returns>
        public override bool IsApplicable(IGateContext context, out IGate[] gates)
        {
            gates = null;
            if (context == null)
            {
                return(false);
            }

            IGate gate = Array.Find(Gates, t => context.IsGateApplicable(t));

            if (gate != null)
            {
                gates = new[] { gate };
                return(true);
            }

            return(false);
        }
Exemple #13
0
        /// <summary>
        /// Executes the given function in the scope of the gates associated with it
        /// </summary>
        /// <remarks>
        /// All code invoked by the function will consider the gates active.
        /// </remarks>
        /// <typeparam name="T">type of the function's result</typeparam>
        /// <param name="gateContext">gate context</param>
        /// <param name="gatedFunction">gated function to execute</param>
        /// <returns>result returned by the function</returns>
        public static T PerformGatedFunctionInScope <T>(this IGateContext gateContext, GatedFunc <T> gatedFunction)
        {
            foreach (IGate gate in gatedFunction.Gates.Gates)
            {
                gateContext.EnterScope(gate);
            }

            try
            {
                return(gatedFunction.Func == null ? default(T) : gatedFunction.Func());
            }
            finally
            {
                foreach (IGate gate in gatedFunction.Gates.Gates)
                {
                    gateContext.ExitScope(gate);
                }
            }
        }
Exemple #14
0
        /// <summary>
        /// Runs the given action in the scope of the gates associated with it
        /// </summary>
        /// <remarks>
        /// All code invoked by the action will consider the gates active.
        /// </remarks>
        /// <param name="gateContext">gate context</param>
        /// <param name="gatedAction">gated action to run</param>
        public static void PerformGatedActionInScope(this IGateContext gateContext, GatedAction gatedAction)
        {
            foreach (IGate gate in gatedAction.Gates.Gates)
            {
                gateContext.EnterScope(gate);
            }

            try
            {
                gatedAction.Action?.Invoke();
            }
            finally
            {
                foreach (IGate gate in gatedAction.Gates.Gates)
                {
                    gateContext.ExitScope(gate);
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Select a code
        /// </summary>
        /// <typeparam name="T">type of gated code</typeparam>
        /// <param name="context">gate context</param>
        /// <param name="conditionalPredicate">The conditional predicate.</param>
        /// <param name="code">array of gated code</param>
        /// <returns>Tuple of gated code and applicaple gate.</returns>
        public static Tuple <T, IGate[]> SelectCode <T>(this IGateContext context, Func <bool> conditionalPredicate, params T[] code) where T : GatedCode
        {
            if (context == null || code == null)
            {
                return(null);
            }

            Lazy <bool> conditionalPredicateIsFalse = new Lazy <bool>(
                () => conditionalPredicate != null && !conditionalPredicate());

            IGate[] gates     = null;
            T       gatedCode = Array.Find(code,
                                           t =>
            {
                if (t != null)
                {
                    if (t.IsBaselineCode)
                    {
                        return(true);
                    }

                    if (!conditionalPredicateIsFalse.Value)
                    {
                        IGate[] applicableGates;
                        if (t.Gates.IsApplicable(context, out applicableGates))
                        {
                            gates = applicableGates;
                            return(true);
                        }
                    }
                }

                return(false);
            });

            if (gatedCode == null)
            {
                return(null);
            }

            return(new Tuple <T, IGate[]>(gatedCode, gates));
        }
Exemple #16
0
        /// <summary>
        /// Checks for gate applicability
        /// </summary>
        /// <param name="context">The current gate context.</param>
        /// <param name="gates">A collection containing the applicable gates.</param>
        /// <returns>True if all the gates are applicable, false otherwise.</returns>
        public override bool IsApplicable(IGateContext context, out IGate[] gates)
        {
            gates = null;

            if (context == null)
            {
                return(false);
            }

            if (Array.Exists(Gates, t => !context.IsGateApplicable(t)))
            {
                return(false);
            }

            if (Gates != null && Gates.Length != 0)
            {
                gates = Gates;
                return(true);
            }

            return(false);
        }
Exemple #17
0
        /// <summary>
        /// Select an applicable action without executing it
        /// </summary>
        /// <param name="context">gate context</param>
        /// <param name="mode">mode to run the gated code in</param>
        /// <param name="conditionalPredicate">The conditional predicate.</param>
        /// <param name="actions">array of gated actions</param>
        /// <returns>an action to perform, never null</returns>
        public static Action SelectAction(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, params GatedAction[] actions)
        {
            Tuple <GatedAction, IGate[]> action = SelectCode(context, conditionalPredicate, actions);

            if (action != null && action.Item1 != null)
            {
                return(new Action(
                           () =>
                {
                    context.EnterScopes(mode, action.Item2);

                    try
                    {
                        action.Item1.Action?.Invoke();
                    }
                    finally
                    {
                        context.ExitScopes(mode, action.Item2);
                    }
                }));
            }

            return(new Action(() => { }));
        }
Exemple #18
0
 /// <summary>
 /// Perform an action that is applicable in the current gate context
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="actions">array of gated actions</param>
 public static Task PerformAction(this IGateContext context, params GatedAsyncAction[] actions) => SelectAction(context, actions)();
Exemple #19
0
 /// <summary>
 /// Is the gate combination applicable
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="gates">applicable gates, can be null even if gate combination is applicable</param>
 /// <returns>true if the gate combination is applicable</returns>
 public abstract bool IsApplicable(IGateContext context, out IGate[] gates);
Exemple #20
0
 /// <summary>
 /// Retrieve the requested gates as a string
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="separator">optional separator</param>
 /// <returns>string representation</returns>
 public static string RequestedGatesAsString(this IGateContext context, string separator = null)
 {
     return(context != null && context.Request != null?
            GatesAsString(context.Request.RequestedGateIds, separator) : null);
 }
Exemple #21
0
 /// <summary>
 /// Perform a function that is applicable in the current gate context based on the passed predicate.
 /// </summary>
 /// <typeparam name="T">Generic type.</typeparam>
 /// <param name="context">The context.</param>
 /// <param name="conditionalPredicate">The conditional predicate.</param>
 /// <param name="functions">The functions.</param>
 /// <returns>Func to perform, (default if no applicable action found)</returns>
 public static T PerformConditionalFunction <T>(this IGateContext context, Func <bool> conditionalPredicate,
                                                params GatedFunc <T>[] functions) => SelectFunction(context, GatedCode.Modes.Scoped, conditionalPredicate, functions)();
Exemple #22
0
 /// <summary>
 /// Perform an action based on a condition that is specified using predicate.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="conditionalPredicate">The conditional predicate.</param>
 /// <param name="actions">The actions.</param>
 public static Task PerformConditionalAction(this IGateContext context, Func <bool> conditionalPredicate,
                                             params GatedAsyncAction[] actions) => SelectAction(context, GatedCode.Modes.Scoped, conditionalPredicate, actions)();
Exemple #23
0
 /// <summary>
 /// Retrieve the activated gates as a string
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="separator">optional separator</param>
 /// <returns>string representation</returns>
 public static string ActivatedGatesAsString(this IGateContext context, string separator = null)
 {
     return(context != null && context.ActivatedGates != null?
            GatesAsString(context.ActivatedGates.Select(gate => gate.Name), separator) : null);
 }
Exemple #24
0
 /// <summary>
 /// Select an applicable function without executing it
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="functions">array of gated functions</param>
 /// <returns>a function to perform, never null</returns>
 public static Func <T, T> SelectFunction <T>(this IGateContext context, params GatedFunc <T, T>[] functions)
 {
     return(SelectFunction(context, GatedCode.Modes.Scoped, functions));
 }
Exemple #25
0
 /// <summary>
 /// Retrieve the current active gates as a string
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="separator">optional separator</param>
 /// <returns>string representation</returns>
 public static string CurrentGatesAsString(this IGateContext context, string separator = null)
 {
     return(context != null?
            GatesAsString(context.CurrentGates, separator) : null);
 }
Exemple #26
0
 /// <summary>
 /// Select an applicable function without executing it
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="functions">array of gated functions</param>
 /// <returns>a function to perform, never null</returns>
 public static Func <Task <T> > SelectFunction <T>(this IGateContext context, params GatedAsyncFunc <T>[] functions)
 {
     return(SelectFunction(context, GatedCode.Modes.Scoped, null, functions));
 }
Exemple #27
0
 /// <summary>
 /// Select an applicable function without executing it
 /// </summary>
 /// <typeparam name="T">Generic type</typeparam>
 /// <param name="context">gate context</param>
 /// <param name="mode">mode to run the gated code in</param>
 /// <param name="conditionalPredicate">The conditional predicate.</param>
 /// <param name="functions">array of gated functions</param>
 /// <returns>a function to perform, never null</returns>
 public static Func <Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate,
                                                   params GatedAsyncFunc <T>[] functions)
 {
     return(SelectFunction(context, mode, conditionalPredicate, functions, false));
 }
Exemple #28
0
 /// <summary>
 /// Perform an action that is applicable in the current gate context
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="mode">mode to run the gated code in</param>
 /// <param name="actions">array of gated actions</param>
 public static Task PerformAction(this IGateContext context, GatedCode.Modes mode, params GatedAsyncAction[] actions) => SelectAction(context, mode, null, actions)();
Exemple #29
0
 /// <summary>
 /// Perform an action that is applicable in the current gate context
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="gate">single target gate</param>
 /// <param name="action">action delegate</param>
 public static Task PerformAction(this IGateContext context, IGate gate, Func <Task> action) => SelectAction(context, new GatedAsyncAction(gate, action))();
Exemple #30
0
 /// <summary>
 /// Select an applicable function without executing it
 /// </summary>
 /// <param name="context">gate context</param>
 /// <param name="mode">mode to run the gated code in</param>
 /// <param name="functions">array of gated functions</param>
 /// <returns>a function to perform, never null</returns>
 public static Func <T, Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, params GatedAsyncFunc <T, T>[] functions)
 {
     return(SelectFunction(context, mode, functions, false));
 }