/// <summary>
        /// Sets up a new activity or child workflow as specified by the workflow at the start of the workflow.
        /// </summary>
        /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
        /// <returns>Properly set up decision completed request.</returns>
        public virtual RespondDecisionTaskCompletedRequest OnWorkflowExecutionStarted(WorkflowDecisionContext context)
        {
            var activityState = BuildActivityState(context);

            if (WorkflowSteps == null || WorkflowSteps.Length == 0)
            {
                return CompleteWorkflow("");
            }

            // Since this is the start of the workflow execution, we start off with the first item
            // in the workflow steps
            RespondDecisionTaskCompletedRequest decisionRequest;
            if (WorkflowSteps[0].IsActivity())
            {
                var activity = ((WorkflowActivitySetupContext) WorkflowSteps[0]).Clone();
                Debug.Assert(activity != null, "activity != null");

                // If input string is empty, we pass the input from the caller (in this case, workflow
                // execution start) to the activity
                if (String.IsNullOrEmpty(activity.Input))
                {
                    activity.Input = activityState;
                }

                decisionRequest = ScheduleActivityTask(activity);
            }
            else if (WorkflowSteps[0].IsTimer())
            {
                var timer = ((WorkflowTimerSetupContext) WorkflowSteps[0]).Clone();
                Debug.Assert(timer != null, "timer != null");

                decisionRequest = StartTimer(timer);
            }
            else if (WorkflowSteps[0].IsWorkflow())
            {
                var childWorkflow = ((WorkflowSetupContext) WorkflowSteps[0]).Clone();
                Debug.Assert(childWorkflow != null, "childWorkflow != null");

                // If input string is empty, we pass the input from the caller (in this case, workflow
                // execution start) to the activity
                if (String.IsNullOrEmpty(childWorkflow.Input))
                {
                    childWorkflow.Input = activityState;
                }

                decisionRequest = StartChildWorkflowExecution(childWorkflow);
            }
            else
            {
                throw new Exception("We can only have activity, timer, or workflow as workflow steps");
            }

            return decisionRequest;
        }
        /// <summary>
        /// Constructor for the workflow event processor. 
        /// </summary>
        /// <param name="decisionTask">Decision task passed in from SWF as decision task response.</param>
        /// <param name="workflows">IEnumerable set of string for workflow name and Type for workflow class.</param>
        /// <param name="request">The request used to retrieve <paramref name="decisionTask"/>, which will be used to retrieve subsequent history event pages.</param>
        /// <param name="swfClient">An SWF client.</param>
        public WorkflowEventsProcessor(DecisionTask decisionTask, IEnumerable<KeyValuePair<string, Type>> workflows, PollForDecisionTaskRequest request, IAmazonSimpleWorkflow swfClient)
        {
            // Decision task can't be null.
            if (decisionTask == null)
            {
                throw new ArgumentNullException("decisionTask");
            }

            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Store the decision task and allocate a new decision context and event dictionary which
            // we will use as we walk through the chain of events
            _decisionTask = decisionTask;
            _request = request;
            _decisionContext = new WorkflowDecisionContext();
            _swfClient = swfClient;

            // Set up our events data structure
            _events = new WorkflowEventsIterator(ref decisionTask, _request, _swfClient);
            _workflows = (Dictionary<string, Type>) workflows;
        }
        /// <summary>
        /// Builds the activity state object to pass to the activity.
        /// </summary>
        /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
        /// <returns>The activity state.</returns>
        protected string BuildActivityState(WorkflowDecisionContext context)
        {
            var activityState = new ActivityState {
                StartingInput = context.StartingInput,
                PreviousResult = context.Result
            };

            return JsonConvert.SerializeObject(activityState);
        }
        private RespondDecisionTaskCompletedRequest GetNextRequest(ISetupContext nextStep, WorkflowDecisionContext context, string nextInput)
        {
            // If we don't have anymore steps, complete the workflow
            if (nextStep == null)
            {
                return CompleteWorkflow(context.Result);
            }

            // Found another step
            if (nextStep.IsActivity())
            {
                // Next step is an activity, set up a schedule activity decision
                var activity = ((WorkflowActivitySetupContext) nextStep).Clone();
                activity.Input = nextInput;
                return ScheduleActivityTask(activity);
            }

            if (nextStep.IsTimer())
            {
                // Next step is a timer, set up a start timer decision
                var timer = ((WorkflowTimerSetupContext) nextStep).Clone();
                return StartTimer(timer);
            }

            // Next step is not an activity, set up a child workflow decision
            Debug.Assert(nextStep.IsWorkflow(), "Steps can only be activities, timers, or workflows.");
            var workflow = ((WorkflowSetupContext) nextStep).Clone();
            workflow.Input = nextInput;
            return StartChildWorkflowExecution(workflow);
        }
        public RespondDecisionTaskCompletedRequest OnTimerCanceled(WorkflowDecisionContext context)
        {
            var step = ((WorkflowTimerSetupContext) GetStep(false /* activity completion */, true /* is timer */,
                                                            context.TimerId, null /* step version */));

            switch (step.CancelAction)
            {
                case TimerCanceledAction.CompleteWorkflow:
                    return CompleteWorkflow(context.Result);

                case TimerCanceledAction.CancelWorkflow:
                    return CancelWorkflow(context.Details);

                case TimerCanceledAction.ProceedToNextActivity:
                    var nextStep = GetNextStep(false /* activity completion */, true /* is timer */, context.TimerId, null);

                    var activityState = BuildActivityState(context);
                    return GetNextRequest(nextStep, context, activityState);

                default:
                    throw new InvalidOperationException();
            }
        }
        public RespondDecisionTaskCompletedRequest OnTimerFired(WorkflowDecisionContext context)
        {
            // Fetch the next step
            var nextStep = GetNextStep(false /* activity completion */, true /* is timer */, context.TimerId, null);

            var activityState = BuildActivityState(context);
            return GetNextRequest(nextStep, context, activityState);
        }
 public RespondDecisionTaskCompletedRequest OnTimerStarted(WorkflowDecisionContext context)
 {
     return EmptyDecision();
 }
 public virtual RespondDecisionTaskCompletedRequest OnWorkflowExecutionCancelRequested(WorkflowDecisionContext context)
 {
     return CancelWorkflow(context.Details);
 }
        /// <summary>
        /// Re-tries the child workflow 3 times before failing the workflow.
        /// </summary>
        /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
        /// <returns>Properly set up decision completed request.</returns>
        public virtual RespondDecisionTaskCompletedRequest OnChildWorkflowExecutionTimedOut(WorkflowDecisionContext context)
        {
            var timeoutCount = 0;

            // If we have already re-tried 3 times, fail the workflow
            if (context.Markers.ContainsKey("ChildWorkflowTimeoutMarker"))
            {
                timeoutCount = Int32.Parse(context.Markers["ChildWorkflowTimeoutMarker"]);
                if (timeoutCount > 3)
                {
                    return FailWorkflow("Failing workflow after 3 retry attempts.", "OnChildWorkflowExecutionTimedOut");
                }
            }
            
            // Fetch the next step and set it up with the right input and doubled timeout value
            var workflowStep = ((WorkflowSetupContext) GetStep(false /* workflow timed out */, false /* is timer */,
                                                               context.ChildWorkflowName, context.ChildWorkflowVersion)).Clone();
            switch (context.TimeoutType)
            {
                case "START_TO_CLOSE":
                    workflowStep.ExecutionStartToCloseTimeout =
                        (Int32.Parse(workflowStep.ExecutionStartToCloseTimeout) * 1 /*timeoutCount*/).ToString(CultureInfo.InvariantCulture);
                    break;

                default:
                    Debug.Assert(false, "Unknown timeout type " + context.TimeoutType);
                    break;
            }

            if (String.IsNullOrEmpty(workflowStep.Input))
            {
                workflowStep.Input = "";
            }
            
            // Fetch the decision to start the child workflow execution
            var request = StartChildWorkflowExecution(workflowStep);

            // Fetch the decision for a new timeout marker and add it to the child workflow request
            var marker = RecordMarker(timeoutCount.ToString(CultureInfo.InvariantCulture), "ChildWorkflowTimeoutMarker");
            request.Decisions.Add(marker.Decisions[0]);

            // Return the combined request
            return request;
        }
        /// <summary>
        /// Set up a fail workflow decision in the event of a failure of scheduling a task.
        /// </summary>
        /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
        /// <returns>Properly set up decision completed request.</returns>
        public virtual RespondDecisionTaskCompletedRequest OnChildWorkflowExecutionCompleted(WorkflowDecisionContext context)
        {
            // Fetch the next step
            var nextStep = GetNextStep(false /* workflow completion */, false /* is timer */,
                                       context.ChildWorkflowName, context.ChildWorkflowVersion);

            var activityState = BuildActivityState(context);
            return GetNextRequest(nextStep, context, activityState);
        }
 /// <summary>
 /// Handles the child workflow execution started by returning an empty decision. This could be modified in the
 /// future to handle parallel child workflow/activity invocations.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnChildWorkflowExecutionStarted(WorkflowDecisionContext context)
 {
     return EmptyDecision();
 }
 /// <summary>
 /// Set up a fail workflow decision in the event of a failure of scheduling a task.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnScheduleActivityTaskFailed(WorkflowDecisionContext context)
 {
     return FailWorkflow(context.Cause, "OnScheduleActivityTaskFailed");
 }
        /// <summary>
        /// Re-tries the activity 3 times before failing the workflow.
        /// </summary>
        /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
        /// <returns>Properly set up decision completed request.</returns>
        public virtual RespondDecisionTaskCompletedRequest OnActivityTaskTimedOut(WorkflowDecisionContext context)
        {
            var timeoutCount = 0;
            var activityState = BuildActivityState(context);

            // If we have already re-tried 3 times, fail the workflow
            if (context.Markers.ContainsKey("ActivityTimeoutMarker"))
            {
                timeoutCount = Int32.Parse(context.Markers["ActivityTimeoutMarker"]);
                if (timeoutCount > 3)
                {
                    return FailWorkflow("Failing workflow after 3 retry attempts.", "OnActivityTaskTimedOut");
                }
            }

            // Bump the timeoutCount
            timeoutCount++;

            // Fetch the next step and set it up with the right input and increased timeout value
            var workflowStep = ((WorkflowActivitySetupContext) GetStep(true /* activity timed out */, false /* is timer */,
                                                                       context.ActivityName, context.ActivityVersion)).Clone();
            switch (context.TimeoutType)
            {
                case "START_TO_CLOSE":
                    workflowStep.StartToCloseTimeout =
                        (Int32.Parse(workflowStep.StartToCloseTimeout) * timeoutCount).ToString(CultureInfo.InvariantCulture);
                    break;

                case "SCHEDULE_TO_START":
                    workflowStep.ScheduleToStartTimeout =
                        (Int32.Parse(workflowStep.ScheduleToStartTimeout) * timeoutCount).ToString(CultureInfo.InvariantCulture);
                    break;

                case "SCHEDULE_TO_CLOSE":
                    workflowStep.ScheduleToCloseTimeout =
                        (Int32.Parse(workflowStep.ScheduleToCloseTimeout) * timeoutCount).ToString(CultureInfo.InvariantCulture);
                    break;

                case "HEARTBEAT":
                    workflowStep.HeartbeatTimeout =
                        (Int32.Parse(workflowStep.HeartbeatTimeout) * timeoutCount).ToString(CultureInfo.InvariantCulture);
                    break;

                default:
                    Debug.Assert(false, "Unknown timeout type " + context.TimeoutType);
                    break;
            }

            if (string.IsNullOrEmpty(workflowStep.Input))
            {
                workflowStep.Input = activityState;
            }

            // Fetch the decision to re-schedule the activity
            var request = ScheduleActivityTask(workflowStep);

            // Fetch the decision for a new timeout marker and add it to the schedule activity request
            var marker = RecordMarker(timeoutCount.ToString(CultureInfo.InvariantCulture), "ActivityTimeoutMarker");
            request.Decisions.Add(marker.Decisions[0]);

            // Return the combined request
            return request;
        }
 /// <summary>
 /// Set up a fail workflow decision in the event of an activity failing.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnActivityTaskFailed(WorkflowDecisionContext context)
 {
     return FailWorkflow(context.Details, context.Reason);
 }
 /// <summary>
 /// Set up a fail workflow decision in the event of failure to start a child workflow.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnStartChildWorkflowExecutionFailed(WorkflowDecisionContext context)
 {
     return FailWorkflow(context.Cause, "OnStartChildWorkflowExecutionFailed");
 }
 /// <summary>
 /// Sets up a new activity or child workflow as specified by the workflow at the re-start of the workflow.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnWorkflowExecutionContinuedAsNew(
     WorkflowDecisionContext context)
 {
     return(OnWorkflowExecutionStarted(context));
 }
 /// <summary>
 /// Sets up a new activity or child workflow as specified by the workflow at the re-start of the workflow.
 /// </summary>
 /// <param name="context">Workflow decision context supplied by SimpleWorkflowFramework.NET.</param>
 /// <returns>Properly set up decision completed request.</returns>
 public virtual RespondDecisionTaskCompletedRequest OnWorkflowExecutionContinuedAsNew(
     WorkflowDecisionContext context)
 {
     return OnWorkflowExecutionStarted(context);
 }