private void ValidateExpressions(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.ValidateExpressions")) { // Validate the Expressions // - all expressions have a target argument // - no more than one expression can target an argument var allExp = _activityInstanceAsWf.ContainedActivities.SelectMany(a => a.ExpressionMap.Select(e => new { Activity = a, Expression = e })); allExp = allExp.Union(ActivityInstance.ExpressionMap.Select(e => new { Activity = ActivityInstance, Expression = e })).ToList(); foreach (var exp in allExp) { var e = exp.Expression; if (e.ArgumentToPopulate == null) { var s = string.Format("Warning: Expression for \"{0}\" ({1}) missing argument to populate: expression name=\"{2}\" ({3}) value=\"{4}\".", exp.Activity != null ? exp.Activity.Name : "", exp.Activity != null ? exp.Activity.Id.ToString() : "", e.Name ?? "", e.Id, e.GetExpressionDisplayString()); EventLog.Application.WriteWarning(s); //metadata.AddValidationError(s); } } } }
private void ValidateTransitions(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.ValidateTransitions")) { foreach (var tran in metadata.AllTransitions) { if (tran.FromActivity == null || tran.FromExitPoint == null || tran.ToActivity == null) { metadata.AddValidationError( string.Format("Workflow '{0}' does not have one of its transitions ({1}) fully described. It must have a from activity and exit point and a destination. " + "From {2} {3} to {4}", ActivityInstance.Name, tran.Id, tran.FromActivity != null ? tran.FromActivity.Name ?? tran.FromActivity.Id.ToString() : "null", tran.FromExitPoint != null ? tran.FromExitPoint.Name ?? tran.FromExitPoint.Id.ToString() : "null", tran.ToActivity != null ? tran.ToActivity.Name ?? tran.FromActivity.Id.ToString() : "null" )); } // validate that all transitions point to children of the workflow if (tran.ToActivity != null && (tran.ToActivity.ContainingWorkflow == null || tran.ToActivity.ContainingWorkflow.Id != _activityInstanceAsWf.Id)) { metadata.AddValidationError(string.Format("Activity '{0}' is not a child of the workflow but is part of a transition", tran.FromActivity.Name)); } } } }
/// <summary> /// Validate the activity, adding any validation errors to the metadata /// </summary> /// <param name="metadata"></param> public virtual void Validate(WorkflowMetadata metadata) { using (Profiler.Measure("ActivityImplementationBase.Validate")) { var manditoryArgs = ActivityInstance.GetInputArguments().Where(arg => arg.ArgumentIsMandatory ?? false); // we can't validate inputs unless we are part of a workflow if (ActivityInstance.ContainingWorkflow == null) { return; } foreach (var manditoryArg in manditoryArgs) { var expression = metadata.GetPopulatedBy(ActivityInstance, manditoryArg); if (expression == null) { metadata.AddValidationError( string.Format( "Mandatory arguments must be given a value. Activity: '{0}' Argument: '{1}'", ActivityInstance.Name, manditoryArg.Name)); } } } }
public RunState(WorkflowMetadata metaData, WorkflowRun workflowRun, RequestContextData effectiveSecurityContext) : base(metaData, workflowRun, effectiveSecurityContext) { ownerAccountRuntimeArgName = Entity.GetName(new EntityRef("workflowOwnerAccount").Id); triggeringUserRuntimeArgName = Entity.GetName(new EntityRef("triggeringUserAccount").Id); triggeringPersonRuntimeArgName = Entity.GetName(new EntityRef("triggeringPerson").Id); }
/// <summary> /// Get the request context this workflow will be running as, taking into account triggering user and owner. /// </summary> private RequestContextData GetEffectiveSecurityContext(WorkflowRun run, WorkflowMetadata metaData) { var effectiveUser = GetEffectiveUser(run, metaData); var triggeringUser = GetTriggeringUser(run); // Error! The caller will deal with the missing info. We can't throw becasue RunState is needed for the error reporting if (effectiveUser == null) { return(null); } if (metaData.WfRunAsOwner && metaData.WfSecurityOwner == null) { return(null); } var identityInfo = new IdentityInfo(effectiveUser.Id, effectiveUser.Name); var context = RequestContext.GetContext(); var effectiveSecurityContext = new RequestContextData(context); effectiveSecurityContext.Identity = identityInfo; // If we are running as someone other than the triggerer, set the secondary identity to the triggerer. // NOTE: This could potentially cause a problem in the case where a wf triggering another wf scenario. // It's possible that the user will see stale data. The risk should be quite low. if (triggeringUser != null && triggeringUser.Id != effectiveUser.Id) { effectiveSecurityContext.SecondaryIdentity = new IdentityInfo(triggeringUser.Id, triggeringUser.Name); } return(effectiveSecurityContext); }
private UserAccount GetEffectiveUser(WorkflowRun run, WorkflowMetadata metaData) { if (metaData != null && metaData.WfRunAsOwner) { return(metaData.WfSecurityOwner); } return(GetTriggeringUser(run)); }
public override void Validate(WorkflowMetadata metadata) { base.Validate(metadata); var activityAs = ActivityInstance.Cast <AssignToVariable>(); if (activityAs.TargetVariable == null) { metadata.AddValidationError(string.Format("Variable has not been assigned. Activity: '{0}'", activityAs.Name)); } }
public RunStateBase(WorkflowMetadata metaData, WorkflowRun _workflowRun, RequestContextData effectiveSecurityContext) : this(metaData) { WorkflowInvoker = new WorkflowInvoker(); WorkflowRun = _workflowRun; StepsTakenInSession = 0; EffectiveSecurityContext = effectiveSecurityContext; ExitPointId = _workflowRun.WorkflowRunExitPoint; HasTimeout = _workflowRun.HasTimeout ?? false; PendingActivity = _workflowRun.PendingActivity; RunStatus = _workflowRun.WorkflowRunStatus_Enum; CompletedAt = _workflowRun.RunCompletedAt; }
public override void Validate(WorkflowMetadata metadata) { base.Validate(metadata); var workflowToProxy = ActivityInstance.As <WorkflowProxy>().WorkflowToProxy; if (workflowToProxy == null) { metadata.AddValidationError("Workflow to run has not been set."); } // // The proxy workflow will be validated separately // }
private void ValidateWorkflowVariables(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.ValidateWorkflowVariables")) { // Validate workflow variables var inputArgumentsNames = _activityInstanceAsWf.InputArguments.Select(arg => arg.Name); foreach (var wfVar in _activityInstanceAsWf.Variables) { if (inputArgumentsNames.Contains(wfVar.Name)) { metadata.AddValidationError(string.Format("Name of variable '{0}' clashed with the input argument of the same name.", wfVar.Name)); } } } }
public override void Validate(WorkflowMetadata metadata) { base.Validate(metadata); var activityInstanceAs = ActivityInstance.Cast <ForEachResource>(); var terminationsCount = activityInstanceAs.ContainingWorkflow.Terminations.Count(t => t.FromActivity.Id == activityInstanceAs.Id); var transitionsCount = activityInstanceAs.ContainingWorkflow.Transitions.Count(t => t.FromActivity.Id == activityInstanceAs.Id); if (transitionsCount + terminationsCount != 2) { metadata.AddValidationError(string.Format("Every 'For Each' activity must have a Loop and a Finish transition. Activity: '{0}'", activityInstanceAs.Name)); } }
/// <summary> /// Create a run state /// </summary> /// <returns>A run state - note the security information will be missing if it has been set incorrectly in the workflow</returns> public IRunState CreateRunState(WorkflowMetadata metaData, WorkflowRun workflowRun) { using (Profiler.Measure("DefaultRunStateFactory.CreateRunState")) { var run = workflowRun; if (!run.IsTemporaryId) { run = run.AsWritable <WorkflowRun>(); } //var effectiveUser = GetEffectiveUser(run, metaData); var effectiveSecurityContext = GetEffectiveSecurityContext(run, metaData); return(new RunState(metaData, run, effectiveSecurityContext)); } }
private void ValidateTerminations(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.ValidateTerminations")) { foreach (var term in _activityInstanceAsWf.Terminations) { if (term.FromActivity == null || term.FromExitPoint == null || term.WorkflowExitPoint == null) { metadata.AddValidationError( string.Format( "Workflow '{0}' does not have one of its terminations fully described. It must have a from activity and exit point and a workflow exit point. From '{1}':'{2}' To:'{3}'", ActivityInstance.Name, term.FromActivity != null ? term.FromActivity.Name ?? "Unnamed activity" : "Activity not specified", term.FromExitPoint != null ? term.FromExitPoint.Name ?? "Unnamed exit" : "Exit not specified", term.WorkflowExitPoint != null ? term.WorkflowExitPoint.Name ?? "Unnamed workflow exit" : "Exit not specified")); } } } }
/// <summary> /// Validate that the reply workflow is marked as RunAsOwner. /// </summary> /// <param name="metadata"></param> public override void Validate(WorkflowMetadata metadata) { base.Validate(metadata); var activityAs = ActivityInstance.Cast <NotifyActivity>(); foreach (var entry in activityAs.NReplyMap) { if (String.IsNullOrWhiteSpace(entry.Name)) { metadata.AddValidationError($"An all entries in the reply mapping must contain a value: '{activityAs.Name}'"); } else if (entry.RmeWorkflow == null) { metadata.AddValidationError($"Mapping entry '{entry.Name}' does not point to a workflow: '{activityAs.Name}'"); } else if (entry.RmeWorkflow.WorkflowRunAsOwner != true) { metadata.AddValidationError($"Mapping entry '{entry.Name}' points to a workflow that is not set to 'Run as owner': '{activityAs.Name}'"); } } }
private void ValidateTransitions2(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.ValidateTransitions2")) { // // Validate that all the transitions from the activities are in the Transitions list var comparer = new EntityIdComparer(); var wfTransAndTerms = ((IEnumerable <IEntity>)_activityInstanceAsWf.Transitions).Union((IEnumerable <IEntity>)_activityInstanceAsWf.Terminations).ToList(); using (Profiler.Measure("WorkflowImplementation.ValidateTransitions2.1")) { foreach (var activity in _activityInstanceAsWf.ContainedActivities) { // validate that all the transitions are on the workflow var missing = activity.ForwardTransitions.Except(wfTransAndTerms, comparer); if (missing.Any()) { metadata.AddValidationError(string.Format("Activity \"{0}\" has a transition that is not listed against the workflow.", activity.Name ?? "(Unnamed)")); } // validate that the transitions have a from exit point on the activity or its type var exitPoints = metadata.GetExitpointsForActivity(activity.Id); foreach (var tran in activity.ForwardTransitions) { if (!exitPoints.Contains(tran.FromExitPoint, comparer)) { metadata.AddValidationError( string.Format("Activity \"{0}\" has a transition whose exit point is not from the origin activity.", activity.Name ?? "(Unnamed)")); } } } } } }
private RunStateBase(WorkflowMetadata metadata) { Metadata = metadata; TimeTakenInSession = new System.Diagnostics.Stopwatch(); }
private IRunState CreateRunState(WorkflowMetadata metadata, WorkflowRun run) { var factory = Factory.Current.Resolve <IRunStateFactory>(); return(factory.CreateRunState(metadata, run)); }
public override void Validate(WorkflowMetadata metadata) { using (Profiler.Measure("WorkflowImplementation.Validate")) { using (new SecurityBypassContext()) { base.Validate(metadata); // validate first activity if (_activityInstanceAsWf.FirstActivity == null) { metadata.AddValidationError("First Activity is missing."); } // ensure that all workflow variables are also in the expression parameters foreach (var v in _activityInstanceAsWf.Variables) { if (_activityInstanceAsWf.ExpressionParameters.All(p => p.ArgumentInstanceArgument.Id != v.Id)) { metadata.AddValidationError(string.Format("Variable '{0}' is missing from the expression parameter list.", v.Name)); } } // ensure the name, activity and argument are defined for the expression parameters foreach (var param in _activityInstanceAsWf.ExpressionParameters) { if (param.Name == null) { metadata.AddValidationError(string.Format("Parameter '{0}' is missing a name.", param.Id)); } if (param.ArgumentInstanceActivity == null || param.ArgumentInstanceArgument == null) { metadata.AddValidationError(string.Format("Parameter '{0}' is missing source information, must have both activity and argument defined.", param.Name)); } } ValidateExpressions(metadata); ValidateWorkflowVariables(metadata); ValidateTransitions(metadata); ValidateTerminations(metadata); ValidateTransitions2(metadata); // // validate first activity // if (_activityInstanceAsWf.FirstActivity == null) { metadata.AddValidationError("The workflow has no first activity."); } // // Validate all the contained activities foreach (var activityInstance in metadata.CachedInstances.Values) { if (activityInstance != this) { activityInstance.Validate(metadata); } } // // Ensure that all activities have unique names. (This ensures that activity outputs cannot have name clashes.) var allNames = _activityInstanceAsWf.ContainedActivities.Select(a => a.Name); var duplicates = allNames.GroupBy(s => s).SelectMany(grp => grp.Skip(1)); if (duplicates.Count() > 0) { metadata.AddValidationError(string.Format("All activities in a workflow must have a unique name: {0}", string.Join(", ", duplicates))); } } } }