public static IWorkflow Instantiate(IWorkplan workplan, IWorkplanContext context)
        {
            // Prepare variables
            var places      = new Dictionary <long, IPlace>();
            var transitions = new List <ITransition>();

            // Iterate over each step and find its connectors
            foreach (var step in workplan.Steps)
            {
                // Create transition
                var transition = step.CreateInstance(context);

                // Set inputs
                for (var i = 0; i < step.Inputs.Length; i++)
                {
                    transition.Inputs[i] = GetPlace(step.Inputs[i], places);
                }

                // Set outputs
                for (int i = 0; i < step.Outputs.Length; i++)
                {
                    transition.Outputs[i] = GetPlace(step.Outputs[i], places);
                }

                transitions.Add(transition);
            }

            return(new SimpleWorkflow(workplan, places.Values.ToList(), transitions));
        }
示例#2
0
        private static IWorkflowEngine CreateEngine(IWorkplan workplan)
        {
            var engine = Workflow.CreateEngine(workplan, new NullContext());

            engine.Completed += (sender, place) => { };
            return(engine);
        }
示例#3
0
        /// <summary>
        /// Extracts the steps of the workplan by using the first output of any step (normally the success path)
        /// </summary>
        /// <param name="workplan">The workplan</param>
        /// <param name="startConnector">Connector for starting the extraction</param>
        /// <param name="endConnector">Connector for ending the extraction</param>
        /// <returns>A sorted list of steps for the path</returns>
        public static IReadOnlyList <IWorkplanStep> ExtractPath(this IWorkplan workplan, IConnector startConnector, IConnector endConnector)
        {
            if (!workplan.Connectors.Contains(startConnector))
            {
                throw new ArgumentException("The start connector is not part of the workplan");
            }

            if (!workplan.Connectors.Contains(endConnector))
            {
                throw new ArgumentException("The end connector is not part of the workplan");
            }

            var path = new List <IWorkplanStep>();

            var currentConnector = startConnector;

            while (currentConnector != null)
            {
                var step = workplan.Steps.First(s => s.Inputs.Contains(currentConnector));
                path.Add(step);

                var output = step.Outputs[0];
                if (output == endConnector)
                {
                    break;
                }

                currentConnector = output;
            }

            return(path);
        }
 internal static WorkplanModel FromWorkplan(IWorkplan wp)
 {
     return(new WorkplanModel
     {
         Id = wp.Id,
         Name = wp.Name,
         Version = wp.Version,
         State = wp.State
     });
 }
示例#5
0
        /// <summary>
        /// Extracts the steps of the workplan by using the first output of any step (normally the success path)
        /// </summary>
        /// <param name="workplan">The workplan</param>
        /// <param name="startConnector">Connector for starting the extraction</param>
        /// <returns>A sorted list of steps for the path</returns>
        public static IReadOnlyList <IWorkplanStep> ExtractPath(this IWorkplan workplan, IConnector startConnector)
        {
            var endConnector = workplan.Connectors.FirstOrDefault(c => c.Classification == NodeClassification.End);

            if (endConnector == null)
            {
                throw new ArgumentException("The workplan does not have any end connector");
            }

            return(ExtractPath(workplan, startConnector, endConnector));
        }
示例#6
0
        public WorkplanModel ConvertWorkplan(IWorkplan workplan)
        {
            var workplanDto = new WorkplanModel
            {
                Id      = workplan.Id,
                Name    = workplan.Name,
                Version = workplan.Version,
                State   = workplan.State
            };

            return(workplanDto);
        }
示例#7
0
        public PathPredictor(IWorkplan workplan)
        {
            // All inputs for each output to traverse the workplan in reverse
            var reversedRelations = ReverseRelations(workplan);

            _workplanAnalysis = reversedRelations.Keys.ToDictionary(key => key, key => new PossibleResults(key));

            foreach (var connector in workplan.Connectors.Where(c => c.Classification.HasFlag(NodeClassification.Exit)))
            {
                Analyze(connector, connector, reversedRelations);
            }
        }
        /// <summary>
        /// Validates the specified workplan.
        /// </summary>
        /// <param name="workplan">The workplan.</param>
        /// <exception cref="ValidationException">
        /// Error during 'DeadEnd'-Validation
        /// or
        /// Error during 'InfiniteLoop'-Validation
        /// or
        /// Error during 'LoneWolf'-Validation
        /// or
        /// Error during 'LuckStreak'-Validation
        /// </exception>
        public static void Validate(this IWorkplan workplan)
        {
            const ValidationAspect aspects = ValidationAspect.DeadEnd | ValidationAspect.InfiniteLoop | ValidationAspect.LoneWolf | ValidationAspect.LuckyStreak;
            var result = Workflow.Validate(workplan, aspects);

            if (result.Success)
            {
                return;
            }

            foreach (var error in result.Errors)
            {
                throw new ValidationException(error.Print(workplan));
            }
        }
        /// <summary>
        /// Create step from another workflow
        /// </summary>
        protected SubWorkplanStep(IWorkplan workplan)
        {
            Workplan = workplan;

            // Step outputs are created from all exits of the sub workflow
            OutputDescriptions = (from connector in workplan.Connectors
                                  where connector.Classification.HasFlag(NodeClassification.Exit)
                                  select new OutputDescription
            {
                Name = connector.Name,
                MappingValue = connector.Id,
                OutputType = connector.Classification == NodeClassification.End ? OutputType.Success : OutputType.Failure
            }).ToArray();
            Outputs = new IConnector[OutputDescriptions.Length];
        }
        /// <summary>
        /// Validate the workplan under different aspects. Aspects can be combined using '|' operator.
        /// </summary>
        /// <param name="workplan">Workplan to validate</param>
        /// <param name="aspects">Enum flag aspects to validate</param>
        /// <returns><remarks>True</remarks> if validation succeeded. Otherwise <remarks>false</remarks>.</returns>
        public static ValidationResult Validate(IWorkplan workplan, ValidationAspect aspects)
        {
            var valid  = true;
            var errors = new List <ValidationError>();

            foreach (var validator in Validators)
            {
                if (aspects.HasFlag(validator.TargetAspect))
                {
                    valid &= validator.Validate(workplan, errors);
                }
            }

            return(new ValidationResult
            {
                Success = valid,
                Errors = errors.ToArray()
            });
        }
示例#11
0
        /// <summary>
        /// Reverse the relations from outputs to inputs to traverse the workplan
        /// in reverse and identify all possible path leading to a certain result
        /// </summary>
        /// <param name="workplan"></param>
        /// <returns></returns>
        private static IDictionary <long, HashSet <IWorkplanNode> > ReverseRelations(IWorkplan workplan)
        {
            // Create dictionary of node ids and possible inputs
            var reversedConnections = workplan.Connectors.Cast <IWorkplanNode>().Concat(workplan.Steps)
                                      .ToDictionary(c => c.Id, c => new HashSet <IWorkplanNode>());

            foreach (var step in workplan.Steps)
            {
                // The input for each output is the step itself
                foreach (var output in step.Outputs)
                {
                    reversedConnections[output.Id].Add(step);
                }

                // The input of the step ar its inputs
                reversedConnections[step.Id].AddRange(step.Inputs);
            }

            return(reversedConnections);
        }
示例#12
0
        /// <summary>
        /// Validate the given workplan
        /// </summary>
        public bool Validate(IWorkplan workplan, ICollection <ValidationError> errors)
        {
            foreach (var connector in workplan.Connectors)
            {
                // Find a step using the connector as input
                if (workplan.Steps.Any(step => step.Inputs.Contains(connector)))
                {
                    continue;
                }

                //  or if it is the end connector
                if (connector.Classification.HasFlag(NodeClassification.Exit))
                {
                    continue;
                }

                errors.Add(new DeadEndValidationError(connector.Id));
            }
            return(errors.Count == 0);
        }
示例#13
0
        /// <summary>
        /// Validate the given workplan
        /// </summary>
        public bool Validate(IWorkplan workplan, ICollection <ValidationError> errors)
        {
            // Iterate over every step and find all steps without inputs or inputs that are not connected
            foreach (var step in workplan.Steps)
            {
                // Check if the step has inputs that a are used somewhere else as outputs
                if (step.Inputs.Length > 0 && step.Inputs.All(input => workplan.Steps.Any(otherStep => otherStep.Outputs.Contains(input))))
                {
                    continue;
                }

                // If we are linked to the start place we can skip too
                if (step.Inputs.Any(input => input.Classification.HasFlag(NodeClassification.Entry)))
                {
                    continue;
                }

                errors.Add(new LoneWolfValidationError(step.Id));
            }
            return(errors.Count == 0);
        }
示例#14
0
        /// <summary>
        /// Print error in readable format
        /// </summary>
        // TODO: Does it make sense to pass workplan to error
        public override string Print(IWorkplan workplan)
        {
            var targetStep = workplan.Steps.First(step => step.Id == PositionId);

            return($"Step {targetStep.Name} at position {PositionId} is unreachable!");
        }
示例#15
0
        /// <summary>
        /// Print error in readable format
        /// </summary>
        public override string Print(IWorkplan workplan)
        {
            var connector = workplan.Connectors.First(c => c.Id == PositionId);

            return($"Connector {connector.Name} at position {PositionId} is not used as an input in any step!");
        }
 /// <summary>
 /// Create step from workplan
 /// </summary>
 public SubworkflowStep(IWorkplan workplan) : base(workplan)
 {
 }
        /// <summary>
        /// Print error in readable format
        /// </summary>
        public override string Print(IWorkplan workplan)
        {
            var connector = workplan.Connectors.First(c => c.Id == PositionId);

            return(string.Format("Connector {0} at postion {1} is not used as an input in any step!", connector.Name, PositionId));
        }
 /// <summary>
 /// Print error in readable format
 /// </summary>
 // TODO: Does it make sense to pass workplan to error
 public abstract string Print(IWorkplan workplan);
示例#19
0
 /// <summary>
 /// Validate the workplan under different aspects. Aspects can be combined using '|' operator.
 /// </summary>
 /// <param name="workplan">Workplan to validate</param>
 /// <param name="aspects">Enum flag aspects to validate</param>
 /// <returns><remarks>True</remarks> if validation succeeded. Otherwise <remarks>false</remarks>.</returns>
 public static ValidationResult Validate(IWorkplan workplan, ValidationAspect aspects)
 {
     return(WorkflowValidation.Validate(workplan, aspects));
 }
示例#20
0
 /// <summary>
 /// Create a path predictor for this workplan that can be used
 /// to monitor instances of the workplan.
 /// </summary>
 public static IPathPredictor PathPrediction(IWorkplan workplan)
 {
     return(new PathPredictor(workplan));
 }
示例#21
0
 /// <summary>
 /// Create engine instance from workplan and context. The default factory will be used to instantiate
 /// the workflow.
 /// </summary>
 public static IWorkflowEngine CreateEngine(IWorkplan workplan, IWorkplanContext context)
 {
     return(CreateWorkflowEngine(WorkflowFactory.Instantiate(workplan, context), context));
 }
 /// <summary>
 /// Constructor to create workflow from places and transistions
 /// </summary>
 public SimpleWorkflow(IWorkplan workplan, IReadOnlyList <IPlace> places, IReadOnlyList <ITransition> transitions)
 {
     Workplan    = workplan;
     Places      = places;
     Transitions = transitions;
 }
示例#23
0
        /// <summary>
        /// Print error in readable format
        /// </summary>
        // TODO: Does it make sense to pass workplan to error
        public override string Print(IWorkplan workplan)
        {
            var targetStep = workplan.Steps.First(step => step.Id == PositionId);

            return(string.Format("Step {0} at position {1} is unreachable!", targetStep.Name, PositionId));
        }