protected virtual string CreateLabel(object[] input, GeneralTransformationRule rule) { var sb = new StringBuilder(); sb.Append("["); if (input[0] != null) { sb.Append(input[0].ToString()); } else { sb.Append("(null)"); } for (int i = 1; i < input.Length; i++) { sb.Append(","); if (input[i] != null) { sb.Append(input[i].ToString()); } else { sb.Append("(null)"); } } sb.Append("], "); sb.Append(rule.ToString()); return(sb.ToString()); }
/// <summary> /// Creates a computation mock for the given transformation rule with the given input and the given context and adds the computation to the context /// </summary> /// <param name="transformationRule">The transformation rule for this computation mock</param> /// <param name="input">The input for this computation</param> /// <returns>The computation mock</returns> public MockComputation Add(GeneralTransformationRule transformationRule, object[] input) { var c = new MockComputation(input, transformationRule, CreateComputationContext()); Add(c); return(c); }
public MockComputation Add <TIn>(GeneralTransformationRule <TIn> transformationRule, TIn input) where TIn : class { var c = new MockComputation(new object[] { input }, transformationRule, CreateComputationContext()); Add(c); return(c); }
protected TaskParallelComputationContext CreateComputationContext(GeneralTransformationRule rule) { var compCon = new TaskParallelComputationContext(this); compCon.DelayOutputAtLeast(rule.OutputDelayLevel); compCon.DelayTransformationAtLeast(rule.TransformationDelayLevel); return(compCon); }
public MockComputation Add <TIn1, TIn2>(GeneralTransformationRule <TIn1, TIn2> transformationRule, TIn1 input1, TIn2 input2) where TIn1 : class where TIn2 : class { var c = new MockComputation(new object[] { input1, input2 }, transformationRule, CreateComputationContext()); Add(c); return(c); }
public static TRule SyncRule <TRule>(this GeneralTransformationRule rule) where TRule : class { var synchronization = rule.Transformation as Synchronization; if (synchronization != null) { return(synchronization.GetSynchronizationRuleForType(typeof(TRule)) as TRule); } return(null); }
private static void CheckTransformationRule <TOut>(object[] input, GeneralTransformationRule startRule) where TOut : class { if (!(startRule is TransformationRuleBase <TOut>) && !startRule.OutputType.IsAssignableFrom(typeof(TOut))) { throw new InvalidOperationException("The output type of the specified start rule does not match the expected result type! Please provide a different start rule."); } if (!startRule.InputType.IsInstanceArrayOfType(input)) { throw new InvalidOperationException("The input parameter types of the specified start rule do not match the given inputs. Please choose a different start rule."); } }
/// <summary> /// Trace the output of the computation that transformed the given input with the given transformation type /// </summary> /// <param name="rule">The rule that transformed the argument</param> /// <param name="input">The input arguments</param> /// <param name="trace">The trace component that is used as basis</param> /// <returns>The output of the computation with the specified input argument or null, if there is none such</returns> public static object ResolveIn(this ITransformationTrace trace, GeneralTransformationRule rule, object[] input) { if (trace == null) { throw new ArgumentNullException("trace"); } var comp = trace.TraceIn(rule, input).FirstOrDefault(); return(comp != null ? comp.Output : null); }
/// <summary> /// Traces the computation based upon the specified input with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule the object was transformed with</param> /// <returns>The computation or null, if there was none</returns> /// <param name="input">The input arguments</param> public override IEnumerable <ITraceEntry> TraceIn(GeneralTransformationRule rule, params object[] input) { if (rule == null) { throw new ArgumentNullException("rule"); } List <ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { return(comps.Where(c => c.TransformationRule == rule)); } return(Enumerable.Empty <ITraceEntry>()); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <returns>The computation that handles this request</returns> public virtual Computation CallTransformation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context) { if (transformationRule == null) { throw new ArgumentNullException("transformationRule"); } var c = Trace.TraceIn(transformationRule, input).OfType <Computation>().FirstOrDefault(); if (c == null) { c = transformationRule.CreateComputation(input, new ComputationContext(this)); computations.Add(c); } return(c); }
/// <summary> /// Traces all computations with any inputs that math the given filters with the specified transformation rule /// </summary> /// <param name="rule">The transformation rule</param> /// <returns>A collection with all computations made under these circumstances</returns> public override IEnumerable <ITraceEntry> TraceAllIn(GeneralTransformationRule rule) { if (rule == null) { throw new ArgumentNullException("rule"); } List <ITraceEntry> comps; if (computationsByTransformationRule.TryGetValue(rule, out comps)) { return(comps.AsReadOnly()); } else { return(Enumerable.Empty <Computation>()); } }
private static void ReorderStack(GeneralTransformationRule originalTransformationRule, Computation comp, Stack <GeneralTransformationRule> ruleStack) { var testTransformationRule = originalTransformationRule; var missingStack = new Stack <GeneralTransformationRule>(); while (!ruleStack.Contains(testTransformationRule)) { missingStack.Push(testTransformationRule); testTransformationRule = testTransformationRule.BaseRule; } while (ruleStack.Peek() != testTransformationRule) { ruleStack.Pop(); if (ruleStack.Count == 0) { throw new InvalidOperationException("The rule stack from the transformation rule did not contain the base rule of the computation"); } } while (missingStack.Count > 0) { testTransformationRule = missingStack.Pop(); ruleStack.Push(testTransformationRule); } while (!testTransformationRule.IsLeafTransformation) { var found = false; foreach (var next in testTransformationRule.Children) { if (next.IsInstantiating(comp)) { testTransformationRule = next; ruleStack.Push(next); found = true; break; } } if (!found) { break; } } }
/// <summary> /// Traces the computations of the specified inputs with the specified transformation rules /// </summary> /// <param name="rule">The transformation rules that transformed the specified inputs</param> /// <param name="inputs">A collection of input arguments</param> /// <returns>A collection of computations</returns> public override IEnumerable <ITraceEntry> TraceManyIn(GeneralTransformationRule rule, IEnumerable <object[]> inputs) { if (rule == null) { throw new ArgumentNullException("rule"); } if (inputs == null) { return(Enumerable.Empty <ITraceEntry>()); } List <ITraceEntry> result = new List <ITraceEntry>(); foreach (var input in inputs) { List <ITraceEntry> comps; if (computationsMade.TryGetValue(input, out comps)) { result.AddRange(comps.Where(c => c.TransformationRule == rule)); } } return(result); }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="filter">The filter that should filter the inputs where this transformation rule is marked instantiating</param> /// <param name="rule">The transformation rule</param> public void MarkInstantiatingFor(GeneralTransformationRule rule, Predicate <object[]> filter) { if (rule == null) { throw new ArgumentNullException("rule"); } if (rule.InputType.IsAssignableArrayFrom(InputType) && rule.OutputType.IsAssignableFrom(OutputType)) { if (filter != null) { MarkInstantiatingFor(rule, (Computation c) => HasCompliantInput(c) && filter(c.CreateInputArray())); } else { MarkInstantiatingFor(rule); } } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingMustInherit); } }
/// <summary> /// Marks the current transformation rule instantiating for the specified rule /// </summary> /// <param name="filter">The filter that should filter the inputs where this transformation rule is marked instantiating</param> /// <param name="rule">The transformation rule</param> public void MarkInstantiatingFor(GeneralTransformationRule rule, Predicate <object[]> filter) { if (rule == null) { throw new ArgumentNullException("rule"); } if (rule.InputType.IsAssignableArrayFrom(InputType) && (rule.OutputType == typeof(void))) { Require(rule); if (filter != null) { MarkInstantiatingFor(rule, o => InputType.IsInstanceArrayOfType(o) && filter(o)); } else { MarkInstantiatingFor(rule, InputType.IsInstanceArrayOfType); } } else { throw new InvalidOperationException(Resources.ErrMarkInstantiatingMustInherit); } }
public RelationalPatternContext(INotifyEnumerable <TIn> relationalSource, GeneralTransformationRule <TIn> targetRule, ITransformationContext context) { this.Source = relationalSource; this.Context = context; this.TargetRule = targetRule; }
/// <summary> /// Handles the computation internally, i.e. calls dependencies, creates output, manages delays, etc /// </summary> /// <param name="transformationRule">The transformation rule</param> /// <param name="input">The input elements for this computation</param> /// <param name="context">The transformation context</param> /// <param name="computations">The computations for the input</param> /// <param name="originalTransformationRule">The transformation rule of the original call</param> /// <param name="comp">The computation</param> /// <param name="compCon">The computation context</param> private void HandleComputation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context, List <ITraceEntry> computations, GeneralTransformationRule originalTransformationRule, Computation comp, ComputationContext compCon) { // The transformation output is only generated when we are handling the base transformation rule, // because this is always required if (compCon.IsDelayed) { Stack <Computation> dependantComputes = new Stack <Computation>(); var ruleStack = Transformation.ComputeInstantiatingTransformationRulePath(comp); if (transformationRule != originalTransformationRule) { ReorderStack(originalTransformationRule, comp, ruleStack); } var delayLevel = comp.Context.MinOutputDelayLevel; var computes = new List <Computation>(); Computation lastComp = null; while (ruleStack.Count > 0) { var rule = ruleStack.Pop(); var comp2 = FindOrCreateDependentComputation(input, computations, comp, dependantComputes, rule); // in case comp2 is not yet handled, a delay does not yet exist and thus // DelayLevel < minDelayLevel delayLevel = Math.Max(delayLevel, Math.Max(comp2.OutputDelayLevel, comp2.Context.MinOutputDelayLevel)); if (lastComp != null) { lastComp.SetBaseComputation(comp2); } lastComp = comp2; computes.Add(comp2); } // delay the call of dependencies // this prevents the issue arising from computations calling their parents that come later in the stack foreach (var comp2 in dependantComputes) { CallDependencies(comp2, true); } if (delayLevel <= currentOutputDelay) { var createRule = computes[0]; // Generate the output var output = createRule.CreateOutput(context); for (int i = computes.Count - 1; i >= 0; i--) { computes[i].InitializeOutput(output); } if (callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { computes[i].Transform(); } } } else { //Save computations into Delay Delay(delayLevel, computes, context); } if (!callTransformations) { for (int i = computes.Count - 1; i >= 0; i--) { AddToComputationOrder(computes[i], currentTransformationDelay); } } for (int i = computes.Count - 1; i >= 0; i--) { dependencyCallQueue.Enqueue(computes[i]); } } }
protected virtual string CreateId(object[] input, GeneralTransformationRule rule) { counter++; return("node" + counter.ToString()); }
protected sealed override ComputationContext CreateComputationContext(object[] input, GeneralTransformationRule rule) { var context = new TracingComputationContext(CreateId(input, rule), this); nodes.AppendFormat(" <Node Id=\"{0}\" Label=\"{1}\"/>", context.Id, CreateLabel(input, rule)); nodes.AppendLine(); return(context); }
protected override ComputationContext CreateComputationContext(object[] input, GeneralTransformationRule rule) { return(new TaskParallelComputationContext(this)); }
private Computation FindOrCreateDependentComputation(object[] input, List <ITraceEntry> computations, Computation comp, Stack <Computation> dependantComputes, GeneralTransformationRule rule) { lock (computations) { var comp2 = computations.Where(cmp => cmp.TransformationRule == rule).OfType <Computation>().FirstOrDefault(); if (comp2 == null) { comp2 = rule.CreateComputation(input, comp.Context); computations.Add(comp2); AddTraceEntry(comp2); dependantComputes.Push(comp2); } return(comp2); } }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <param name="context">The callers context</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation(GeneralTransformationRule transformationRule, object[] input, IEnumerable context) { if (transformationRule == null) { throw new ArgumentNullException("transformationRule"); } if (input == null) { throw new ArgumentNullException("input"); } List <ITraceEntry> computations; if (!computationsMade.TryGetValue(input, out computations)) { computations = new List <ITraceEntry>(); if (!computationsMade.TryAdd(input, computations)) { computations = computationsMade[input]; } } var originalTransformationRule = transformationRule; while (transformationRule.BaseRule != null) { transformationRule = transformationRule.BaseRule; } Computation comp; TaskParallelComputationContext compCon = null; bool handleComputation; if (transformationRule.IsUnique) { lock (computations) { comp = computations.OfType <Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule); if (comp != null && transformationRule != originalTransformationRule) { transformationRule = originalTransformationRule; while (computations.OfType <Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule.BaseRule) == null) { transformationRule = transformationRule.BaseRule; } comp = computations.OfType <Computation>().FirstOrDefault(cpt => cpt.TransformationRule == transformationRule); } if (comp == null) { handleComputation = true; compCon = CreateComputationContext(transformationRule); comp = transformationRule.CreateComputation(input, compCon); computations.Add(comp); compCon.DelayOutput(new OutputDelay()); } else { handleComputation = false; } } } else { lock (computations) { handleComputation = true; compCon = CreateComputationContext(transformationRule); comp = transformationRule.CreateComputation(input, compCon); computations.Add(comp); compCon.DelayOutput(new OutputDelay()); } } if (handleComputation) { AddTraceEntry(comp); CallDependencies(comp, true); HandleComputation(transformationRule, input, context, computations, originalTransformationRule, comp, compCon); } return(comp); }
/// <summary> /// Creates a new mocked computation /// </summary> /// <param name="input">The input for the mocked computation</param> /// <param name="rule">The transformation rule for the mocked computation</param> /// <param name="context">The transformation context</param> public MockComputation(object[] input, GeneralTransformationRule rule, IComputationContext context) : base(rule, context) { inputs = input; }
public static void ProcessMany <TIn>(IEnumerable <TIn> inputs, ITransformationEngineContext context, GeneralTransformationRule <TIn> startRule) where TIn : class { if (context == null) { throw new ArgumentNullException("context"); } var transformation = context.Transformation; if (!transformation.IsInitialized) { transformation.Initialize(); } if (startRule == null) { startRule = context.Transformation.GetRulesForInputTypes(new Type[] { typeof(TIn) }).FirstOrDefault() as GeneralTransformationRule <TIn>; } else { if (startRule.Transformation != context.Transformation) { ThrowRuleNotPartOfTransformation(); } } TransformationRunner.TransformMany(inputs.Select(item => new object[] { item }), null, startRule, context); }
/// <summary> /// Transforms the input argument into an output using the provided transformation /// </summary> /// <typeparam name="TOut">The desired output type</typeparam> /// <param name="inputs">The input parameters</param> /// <param name="types">The types of the elements within the collection refered to in the inputs parameter</param> /// <param name="startRule">The rule that should be started with. If this is null, an applicable rule is found.</param> /// <param name="context">The context that should be used (must not be null).</param> /// <returns>The output from the transformation</returns> public static IEnumerable <TOut> TransformMany <TOut>(IEnumerable <object[]> inputs, Type[] types, ITransformationEngineContext context, GeneralTransformationRule startRule) where TOut : class { if (context == null) { throw new ArgumentNullException("context"); } if (types == null) { throw new ArgumentNullException("types"); } var transformation = context.Transformation; if (!transformation.IsInitialized) { transformation.Initialize(); } if (startRule == null) { startRule = context.Transformation.GetRuleForTypeSignature(types, typeof(TOut)); } else { if (startRule.Transformation != context.Transformation) { ThrowRuleNotPartOfTransformation(); } } return(TransformationRunner.TransformMany(inputs.Select(item => new object[] { item }), null, startRule, context).Select(c => c.Output).OfType <TOut>()); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation(GeneralTransformationRule transformationRule, object[] input) { return(CallTransformation(transformationRule, null, input)); }
public static void Process <TIn1, TIn2>(TIn1 input1, TIn2 input2, ITransformationEngineContext context, GeneralTransformationRule <TIn1, TIn2> startRule) where TIn1 : class where TIn2 : class { if (context == null) { throw new ArgumentNullException("context"); } var transformation = context.Transformation; if (!transformation.IsInitialized) { transformation.Initialize(); } if (startRule == null) { startRule = context.Transformation.GetRulesForInputTypes(new Type[] { typeof(TIn1), typeof(TIn2) }).FirstOrDefault() as GeneralTransformationRule <TIn1, TIn2>; } else { if (startRule.Transformation != context.Transformation) { ThrowRuleNotPartOfTransformation(); } } TransformationRunner.Transform(new object[] { input1, input2 }, null, startRule, context); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <typeparam name="TIn">The type of the first input parameter</typeparam> /// <param name="input">The input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation <TIn>(GeneralTransformationRule <TIn> transformationRule, TIn input) where TIn : class { return(CallTransformation(transformationRule, null, new object[] { input })); }
/// <summary> /// Transforms the input argument into an output using the provided transformation /// </summary> /// <typeparam name="TOut">The desired output type</typeparam> /// <param name="input">The input parameter</param> /// <param name="startRule">The rule that should be started with. If this is null, an applicable rule is found.</param> /// <param name="context">The context that should be used (must not be null).</param> /// <returns>The output from the transformation</returns> public static TOut Transform <TOut>(object[] input, ITransformationEngineContext context, GeneralTransformationRule startRule) where TOut : class { if (context == null) { throw new ArgumentNullException("context"); } if (input == null) { throw new ArgumentNullException("input"); } var transformation = context.Transformation; if (!transformation.IsInitialized) { transformation.Initialize(); } if (startRule == null) { startRule = context.Transformation.GetRuleForTypeSignature(input.GetTypes(), typeof(TOut)); } else { if (startRule.Transformation != context.Transformation) { ThrowRuleNotPartOfTransformation(); } CheckTransformationRule <TOut>(input, startRule); } return(TransformationRunner.Transform(input, null, startRule, context).Output as TOut); }
/// <summary> /// Calls the given transformation with the specified input /// </summary> /// <typeparam name="TIn1">The type of the first input parameter</typeparam> /// <typeparam name="TIn2">The type of the second input parameter</typeparam> /// <param name="input1">The first input for the transformation rule</param> /// <param name="input2">The second input for the transformation rule</param> /// <param name="transformationRule">The rule that should be applied</param> /// <returns>The computation that handles this request</returns> public Computation CallTransformation <TIn1, TIn2>(GeneralTransformationRule <TIn1, TIn2> transformationRule, TIn1 input1, TIn2 input2) where TIn1 : class where TIn2 : class { return(CallTransformation(transformationRule, null, new object[] { input1, input2 })); }