/// <summary>
        /// Run a workflow step
        /// </summary>
        /// <param name="workflowMessage">Message to pass to the step class</param>
        /// <param name="retryStepTimes">Times to retry on error</param>
        /// <param name="workflowStep">The step to run</param>
        internal void RunFrameworkStep(IWorkflowMessage workflowMessage, int retryStepTimes, ProcessorStep workflowStep, ProcessorJob currentJob, bool isCheckDepends)
        {
            bool impersonated = false;
            if (!string.IsNullOrEmpty(workflowStep.RunAsDomain) && !string.IsNullOrEmpty(workflowStep.RunAsUser) && !string.IsNullOrEmpty(workflowStep.RunAsPassword) && workflowStep.RunMode == FrameworkStepRunMode.STA)
                impersonated = impersonate.ImpersonateValidUser(workflowStep.RunAsUser, workflowStep.RunAsDomain, workflowStep.RunAsPassword);
            using (IStep step = StepFactory.GetStep(workflowStep.InvokeClass))
            {
                try
                {
                    workflowStep.RunStatus = FrameworkStepRunStatus.Loaded;
                    if (isCheckDepends)
                        WaitForDependents(workflowStep, currentJob);
                    workflowStep.StartDate = DateTime.Now;
                    step.RunStep(workflowMessage);
                    workflowStep.EndDate = DateTime.Now;
                    workflowStep.RunStatus = FrameworkStepRunStatus.Complete;
                    workflowStep.ExitMessage = "Complete";
                }
                catch (Exception e)
                {
                    workflowStep.RunStatus = FrameworkStepRunStatus.CompleteWithErrors;
                    workflowStep.ExitMessage = e.Message;
                    while (e.InnerException != null)
                    {
                        e = e.InnerException;
                        workflowStep.ExitMessage += '|' + e.Message;
                    }
                    switch (workflowStep.OnError)
                    {
                        case OnFrameworkStepError.RetryStep:
                            if (workflowStep.WaitBetweenRetriesMilliseconds > 0)
                                Thread.Sleep(workflowStep.WaitBetweenRetriesMilliseconds);
                            // Try the step again
                            retryStepTimes++;
                            if (retryStepTimes <= workflowStep.RetryTimes)
                                RunFrameworkStep(workflowMessage, retryStepTimes, workflowStep, currentJob, isCheckDepends);
                            break;
                        default:
                            // If this is running from a thread, do not throw the error up
                            if (workflowStep.RunMode == FrameworkStepRunMode.STA)
                                throw e;
                            else
                                Processor.ReportJobError(e, workflowStep, workflowMessage, currentJob);
                            break;
                    }
                }
            }

            if (impersonated)
                impersonate.UndoImpersonation();
        }
        /// <summary>
        /// Load the Job's steps
        /// </summary>
        /// <param name="processorJob">The ProcessorJob to load to</param>
        /// <param name="queuesNode">The XmlNode to load from</param>
        private static void LoadJobSteps(ProcessorJob processorJob, XmlNode stepsNode)
        {
            foreach (XmlNode stepNode in stepsNode.ChildNodes)
            {
                ProcessorStep workFlowStep = new ProcessorStep();

                if (!string.IsNullOrEmpty(stepNode.Attributes["Name"].Value)) //Required
                    workFlowStep.StepName = stepNode.Attributes["Name"].Value;
                if (!string.IsNullOrEmpty(stepNode.Attributes["Group"].Value)) //Required
                    workFlowStep.Group = stepNode.Attributes["Group"].Value;
                if (!string.IsNullOrEmpty(stepNode.Attributes["InvokeClass"].Value)) //Required
                    workFlowStep.InvokeClass = stepNode.Attributes["InvokeClass"].Value;
                if (stepNode.Attributes["OnError"] != null && !string.IsNullOrEmpty(stepNode.Attributes["OnError"].Value))
                    workFlowStep.OnError = (OnFrameworkStepError)Enum.Parse(typeof(OnFrameworkStepError), stepNode.Attributes["OnError"].Value, true);
                if (stepNode.Attributes["RetryTimes"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RetryTimes"].Value))
                {
                    int retryTimes = 0;
                    int.TryParse(stepNode.Attributes["RetryTimes"].Value, out retryTimes);
                    workFlowStep.RetryTimes = retryTimes;
                }
                if (stepNode.Attributes["WaitBetweenRetriesMilliseconds"] != null && !string.IsNullOrEmpty(stepNode.Attributes["WaitBetweenRetriesMilliseconds"].Value))
                {
                    int waitBetweenRetriesMilliseconds = 0;
                    int.TryParse(stepNode.Attributes["WaitBetweenRetriesMilliseconds"].Value, out waitBetweenRetriesMilliseconds);
                    workFlowStep.WaitBetweenRetriesMilliseconds = waitBetweenRetriesMilliseconds;
                }
                if (stepNode.Attributes["RunMode"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunMode"].Value))
                    workFlowStep.RunMode = (FrameworkStepRunMode)Enum.Parse(typeof(FrameworkStepRunMode), stepNode.Attributes["RunMode"].Value, true);
                if (stepNode.Attributes["DependsOn"] != null && !string.IsNullOrEmpty(stepNode.Attributes["DependsOn"].Value))
                    workFlowStep.DependsOn = stepNode.Attributes["DependsOn"].Value;
                if (stepNode.Attributes["DependsOnGroup"] != null && !string.IsNullOrEmpty(stepNode.Attributes["DependsOnGroup"].Value))
                    workFlowStep.DependsOnGroup = stepNode.Attributes["DependsOnGroup"].Value;
                if (stepNode.Attributes["WaitForDependsOnMilliseconds"] != null && !string.IsNullOrEmpty(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value))
                {
                    int waitForDependsOnMilliseconds = int.MaxValue;
                    if (!string.IsNullOrEmpty(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value))
                        int.TryParse(stepNode.Attributes["WaitForDependsOnMilliseconds"].Value, out waitForDependsOnMilliseconds);
                    workFlowStep.WaitForDependsOnMilliseconds = waitForDependsOnMilliseconds;
                }
                if (stepNode.Attributes["RunAsDomain"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsDomain"].Value))
                    workFlowStep.RunAsDomain = Utils.GetDecryptedString(stepNode.Attributes["RunAsDomain"].Value);
                if (stepNode.Attributes["RunAsUser"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsUser"].Value))
                    workFlowStep.RunAsUser = Utils.GetDecryptedString(stepNode.Attributes["RunAsUser"].Value);
                if (stepNode.Attributes["RunAsPassword"] != null && !string.IsNullOrEmpty(stepNode.Attributes["RunAsPassword"].Value))
                    workFlowStep.RunAsPassword = Utils.GetDecryptedString(stepNode.Attributes["RunAsPassword"].Value);
                processorJob.WorkFlowSteps.Add(workFlowStep);
            }
        }
        /// <summary>
        /// Block untill all steps and groups this step depends on have finished
        /// </summary>
        /// <param name="workflowStep"></param>
        private void WaitForDependents(ProcessorStep workflowStep, ProcessorJob currentJob)
        {
            if (string.IsNullOrEmpty(workflowStep.DependsOn) &&
                string.IsNullOrEmpty(workflowStep.DependsOnGroup))
                return;

            var result = from ProcessorStep in currentJob.WorkFlowSteps
                         where ProcessorStep.RunStatus != FrameworkStepRunStatus.Complete &&
                         (workflowStep.DependsOn.Split(',').Contains(ProcessorStep.StepName) ||
                         workflowStep.DependsOnGroup.Split(',').Contains(ProcessorStep.Group))
                         select ProcessorStep;
            if (result.Count() > 0) //There are still steps to wait for
            {
                Thread.Sleep(100);
                workflowStep.RunStatusTime += 100;
                if (workflowStep.RunStatusTime <= workflowStep.WaitForDependsOnMilliseconds)
                    WaitForDependents(workflowStep, currentJob);
            }
        }
        /// <summary>
        /// Reports a job error
        /// </summary>
        /// <param name="e">The exception to report</param>
        /// <param name="step">The step the exception accrued</param>
        /// <param name="workflowMessage">The original message pulled from the queue</param>
        public static void ReportJobError(Exception e, ProcessorStep workflowStep, IWorkflowMessage workflowMessage, ProcessorJob currentJob)
        {
            // Push an error message to the error Queue
            WorkflowErrorMessage errorMessage = new WorkflowErrorMessage() { ExceptionMessage = e.Message, JobName = currentJob.JobName, StepName = workflowStep.StepName };

            //if e contains inner exceptions, add those messages
            while (e.InnerException != null)
            {
                //assign e to the inner exception - recursive
                e = e.InnerException;
                errorMessage.ExceptionMessage += '|' + e.Message;
            }

            FrameworkManager.AddFrameworkError(currentJob, workflowMessage, errorMessage);
        }